Backed out 15 changesets (bug 1317101) for e10s jsreftest failures a=backout CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Wed, 16 Nov 2016 16:44:30 -0800
changeset 322863 ed48815cbe18f8c787bb9441e35e6c9fc4c4be42
parent 322862 c428116222e76099999ba5ea0e9178daac7580f9
child 322906 e79cc7c6e7a711948f84c034ffd94e1b30e4f7fd
push id83995
push userkwierso@gmail.com
push dateThu, 17 Nov 2016 00:44:35 +0000
treeherdermozilla-inbound@ed48815cbe18 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1317101
milestone53.0a1
backs out17757ba4c0e82c7300a0b832b1726230cbbe5f29
61f8a4084bbd9bdfda1d2d460f659c880a7deb13
a8cdc81cdcce558592d01d3cc6d0ee66269f1077
e06d269a5d4f35b608b5bc7f1c61e875f2322b45
1e1bfb578dcd24433d43fb67cc1f75e87ba48d21
0f8144296a9d8e67a4f307491559a0051f95a9a7
b7892d3fb0ca5268a252377ecbb44dfb1d289500
039d63d5fef77d7b77c0a7f9724ec9e6347be09a
ef7e061b37bf1337c7832df01664adc1fd504adf
af7b81d7a5cc8bef552e440da1b3dada47507fd5
225ad2535585ff6ce38e1e9f8fe5371194a70658
b0521588011d866ee6b2019ee71654768b9e7677
07321664430ab3416a0aa3a29055012b5eb149c5
47d283897283f33d3590ba5b946cc1e5eb5e44d3
ffc63be3557c3a9531591b28adff6feb0e88e3e3
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
Backed out 15 changesets (bug 1317101) for e10s jsreftest failures a=backout CLOSED TREE Backed out changeset 17757ba4c0e8 (bug 1317101) Backed out changeset 61f8a4084bbd (bug 1317101) Backed out changeset a8cdc81cdcce (bug 1317101) Backed out changeset e06d269a5d4f (bug 1317101) Backed out changeset 1e1bfb578dcd (bug 1317101) Backed out changeset 0f8144296a9d (bug 1317101) Backed out changeset b7892d3fb0ca (bug 1317101) Backed out changeset 039d63d5fef7 (bug 1317101) Backed out changeset ef7e061b37bf (bug 1317101) Backed out changeset af7b81d7a5cc (bug 1317101) Backed out changeset 225ad2535585 (bug 1317101) Backed out changeset b0521588011d (bug 1317101) Backed out changeset 07321664430a (bug 1317101) Backed out changeset 47d283897283 (bug 1317101) Backed out changeset ffc63be3557c (bug 1317101)
browser/base/content/browser.css
browser/base/content/tabbrowser.xml
browser/components/extensions/.eslintrc.js
browser/components/extensions/ext-tabs.js
browser/components/extensions/ext-utils.js
browser/components/extensions/moz.build
browser/components/extensions/test/browser/browser-common.ini
browser/components/extensions/test/browser/browser-remote.ini
browser/components/extensions/test/browser/browser.ini
browser/components/extensions/test/browser/browser_ext_browserAction_popup.js
browser/components/extensions/test/browser/browser_ext_browserAction_popup_resize.js
browser/components/extensions/test/browser/browser_ext_commands_execute_browser_action.js
browser/components/extensions/test/browser/browser_ext_pageAction_popup_resize.js
browser/components/extensions/test/browser/browser_ext_popup_api_injection.js
browser/components/extensions/test/browser/browser_ext_tabs_events.js
browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js
browser/components/extensions/test/browser/head.js
browser/modules/E10SUtils.jsm
dom/base/nsFrameLoader.cpp
mobile/android/chrome/content/browser.css
modules/libpref/init/all.js
python/mozbuild/mozbuild/testing.py
toolkit/components/extensions/Extension.jsm
toolkit/components/extensions/ExtensionChild.jsm
toolkit/components/extensions/ExtensionContent.jsm
toolkit/components/extensions/ExtensionManagement.jsm
toolkit/components/extensions/ExtensionParent.jsm
toolkit/components/extensions/ExtensionTestCommon.jsm
toolkit/components/extensions/ext-backgroundPage.js
toolkit/components/extensions/ext-browser-content.js
toolkit/components/extensions/moz.build
toolkit/components/extensions/test/mochitest/head.js
toolkit/components/extensions/test/mochitest/mochitest-common.ini
toolkit/components/extensions/test/mochitest/mochitest-remote.ini
toolkit/components/extensions/test/mochitest/mochitest.ini
toolkit/components/extensions/test/mochitest/test_ext_webrequest_background_events.html
toolkit/components/extensions/test/mochitest/test_ext_webrequest_basic.html
toolkit/components/viewsource/content/viewSource.css
toolkit/content/xul.css
toolkit/mozapps/extensions/content/extensions.js
toolkit/mozapps/extensions/test/browser/browser_inlinesettings_browser.js
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -90,16 +90,20 @@ panelview {
   transition: transform var(--panelui-subview-transition-duration);
 }
 
 panelview:not([mainview]):not([current]) {
   transition: visibility 0s linear var(--panelui-subview-transition-duration);
   visibility: collapse;
 }
 
+browser[frameType="social"][remote="true"] {
+  -moz-binding: url("chrome://global/content/bindings/remote-browser.xml#remote-browser");
+}
+
 tabbrowser {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser");
 }
 
 .tabbrowser-tabs {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tabs");
 }
 
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -4822,26 +4822,24 @@
           this._tabFilters.set(this.mCurrentTab, filter);
           this.webProgress.addProgressListener(filter, nsIWebProgress.NOTIFY_ALL);
 
           this.style.backgroundColor =
             Services.prefs.getBoolPref("browser.display.use_system_colors") ?
               "-moz-default-background-color" :
               Services.prefs.getCharPref("browser.display.background_color");
 
-          let messageManager = window.getGroupMessageManager("browsers");
-
           let remote = window.QueryInterface(Ci.nsIInterfaceRequestor)
             .getInterface(Ci.nsIWebNavigation)
             .QueryInterface(Ci.nsILoadContext)
             .useRemoteTabs;
           if (remote) {
             messageManager.addMessageListener("DOMTitleChanged", this);
             messageManager.addMessageListener("DOMWindowClose", this);
-            window.messageManager.addMessageListener("contextmenu", this);
+            messageManager.addMessageListener("contextmenu", this);
             messageManager.addMessageListener("Browser:Init", this);
 
             // If this window has remote tabs, switch to our tabpanels fork
             // which does asynchronous tab switching.
             this.mPanelContainer.classList.add("tabbrowser-tabpanels");
           } else {
             this._outerWindowIDBrowserMap.set(this.mCurrentBrowser.outerWindowID,
                                               this.mCurrentBrowser);
@@ -4904,19 +4902,18 @@
                               .getService(nsIEventListenerService);
           els.removeSystemEventListener(document, "keydown", this, false);
           if (this.AppConstants.platform == "macosx") {
             els.removeSystemEventListener(document, "keypress", this, false);
           }
           window.removeEventListener("sizemodechange", this, false);
 
           if (gMultiProcessBrowser) {
-            let messageManager = window.getGroupMessageManager("browsers");
             messageManager.removeMessageListener("DOMTitleChanged", this);
-            window.messageManager.removeMessageListener("contextmenu", this);
+            messageManager.removeMessageListener("contextmenu", this);
 
             if (this._switcher) {
               this._switcher.destroy();
             }
           }
 
           Services.prefs.removeObserver("accessibility.typeaheadfind", this);
         ]]>
--- a/browser/components/extensions/.eslintrc.js
+++ b/browser/components/extensions/.eslintrc.js
@@ -3,17 +3,16 @@
 module.exports = {  // eslint-disable-line no-undef
   "extends": "../../../toolkit/components/extensions/.eslintrc.js",
 
   "globals": {
     "AllWindowEvents": true,
     "browserActionFor": true,
     "currentWindow": true,
     "EventEmitter": true,
-    "getBrowserInfo": true,
     "getCookieStoreIdForTab": true,
     "IconDetails": true,
     "makeWidgetId": true,
     "pageActionFor": true,
     "PanelPopup": true,
     "TabContext": true,
     "ViewPopup": true,
     "WindowEventManager": true,
--- a/browser/components/extensions/ext-tabs.js
+++ b/browser/components/extensions/ext-tabs.js
@@ -20,31 +20,39 @@ Cu.import("resource://gre/modules/Extens
 var {
   EventManager,
   ignoreEvent,
 } = ExtensionUtils;
 
 // This function is pretty tightly tied to Extension.jsm.
 // Its job is to fill in the |tab| property of the sender.
 function getSender(extension, target, sender) {
-  let tabId;
   if ("tabId" in sender) {
-    // The message came from a privileged extension page running in a tab. In
-    // that case, it should include a tabId property (which is filled in by the
-    // page-open listener below).
-    tabId = sender.tabId;
+    // The message came from an ExtensionContext. In that case, it should
+    // include a tabId property (which is filled in by the page-open
+    // listener below).
+    let tab = TabManager.getTab(sender.tabId, null, null);
     delete sender.tabId;
-  } else if (target instanceof Ci.nsIDOMXULElement) {
-    tabId = getBrowserInfo(target).tabId;
-  }
-
-  if (tabId) {
-    let tab = TabManager.getTab(tabId, null, null);
     if (tab) {
       sender.tab = TabManager.convert(extension, tab);
+      return;
+    }
+  }
+  if (target instanceof Ci.nsIDOMXULElement) {
+    // If the message was sent from a content script to a <browser> element,
+    // then we can just get the `tab` from `target`.
+    let tabbrowser = target.ownerGlobal.gBrowser;
+    if (tabbrowser) {
+      let tab = tabbrowser.getTabForBrowser(target);
+
+      // `tab` can be `undefined`, e.g. for extension popups. This condition is
+      // reached if `getSender` is called for a popup without a valid `tabId`.
+      if (tab) {
+        sender.tab = TabManager.convert(extension, tab);
+      }
     }
   }
 }
 
 // Used by Extension.jsm
 global.tabGetSender = getSender;
 
 /* eslint-disable mozilla/balanced-listeners */
@@ -63,23 +71,20 @@ extensions.on("page-shutdown", (type, co
       if (tab) {
         gBrowser.removeTab(tab);
       }
     }
   }
 });
 
 extensions.on("fill-browser-data", (type, browser, data) => {
-  let tabId, windowId;
-  if (browser) {
-    ({tabId, windowId} = getBrowserInfo(browser));
-  }
-
-  data.tabId = tabId || -1;
-  data.windowId = windowId || -1;
+  let gBrowser = browser && browser.ownerGlobal.gBrowser;
+  let tab = gBrowser && gBrowser.getTabForBrowser(browser);
+  data.tabId = tab ? TabManager.getId(tab) : -1;
+  data.windowId = tab ? WindowManager.getId(tab.ownerGlobal) : -1;
 });
 /* eslint-enable mozilla/balanced-listeners */
 
 global.currentWindow = function(context) {
   let {xulWindow} = context;
   if (xulWindow && context.viewType != "background") {
     return xulWindow;
   }
--- a/browser/components/extensions/ext-utils.js
+++ b/browser/components/extensions/ext-utils.js
@@ -118,17 +118,17 @@ class BasePopup {
   }
 
   destroy() {
     this.extension.forgetOnClose(this);
 
     this.destroyed = true;
     this.browserLoadedDeferred.reject(new Error("Popup destroyed"));
     return this.browserReady.then(() => {
-      this.destroyBrowser(this.browser, true);
+      this.destroyBrowser(this.browser);
       this.browser.remove();
 
       this.viewNode.removeEventListener(this.DESTROY_EVENT, this);
       this.viewNode.style.maxHeight = "";
 
       if (this.panel) {
         this.panel.style.removeProperty("--arrowpanel-background");
         this.panel.style.removeProperty("--panel-arrow-image-vertical");
@@ -136,29 +136,26 @@ class BasePopup {
 
       BasePopup.instances.get(this.window).delete(this.extension);
 
       this.browser = null;
       this.viewNode = null;
     });
   }
 
-  destroyBrowser(browser, finalize = false) {
+  destroyBrowser(browser) {
     let mm = browser.messageManager;
     // If the browser has already been removed from the document, because the
-    // popup was closed externally, there will be no message manager here, so
-    // just replace our receiveMessage method with a stub.
+    // popup was closed externally, there will be no message manager here.
     if (mm) {
       mm.removeMessageListener("DOMTitleChanged", this);
       mm.removeMessageListener("Extension:BrowserBackgroundChanged", this);
       mm.removeMessageListener("Extension:BrowserContentLoaded", this);
       mm.removeMessageListener("Extension:BrowserResized", this);
       mm.removeMessageListener("Extension:DOMWindowClose", this);
-    } else if (finalize) {
-      this.receiveMessage = () => {};
     }
   }
 
   // Returns the name of the event fired on `viewNode` when the popup is being
   // destroyed. This must be implemented by every subclass.
   get DESTROY_EVENT() {
     throw new Error("Not implemented");
   }
@@ -223,74 +220,71 @@ class BasePopup {
 
   createBrowser(viewNode, popupURL = null) {
     let document = viewNode.ownerDocument;
     this.browser = document.createElementNS(XUL_NS, "browser");
     this.browser.setAttribute("type", "content");
     this.browser.setAttribute("disableglobalhistory", "true");
     this.browser.setAttribute("transparent", "true");
     this.browser.setAttribute("class", "webextension-popup-browser");
-    this.browser.setAttribute("webextension-view-type", "popup");
     this.browser.setAttribute("tooltip", "aHTMLTooltip");
 
-    if (this.extension.remote) {
-      this.browser.setAttribute("remote", "true");
-    }
-
     // We only need flex sizing for the sake of the slide-in sub-views of the
     // main menu panel, so that the browser occupies the full width of the view,
     // and also takes up any extra height that's available to it.
     this.browser.setAttribute("flex", "1");
 
     // Note: When using noautohide panels, the popup manager will add width and
     // height attributes to the panel, breaking our resize code, if the browser
     // starts out smaller than 30px by 10px. This isn't an issue now, but it
     // will be if and when we popup debugging.
 
-
-    let readyPromise;
-    if (this.extension.remote) {
-      readyPromise = promiseEvent(this.browser, "XULFrameLoaderCreated");
-    } else {
-      readyPromise = promiseEvent(this.browser, "load");
-    }
-
     viewNode.appendChild(this.browser);
 
     extensions.emit("extension-browser-inserted", this.browser);
+    let windowId = WindowManager.getId(this.browser.ownerGlobal);
+    this.browser.messageManager.sendAsyncMessage("Extension:InitExtensionView", {
+      viewType: "popup",
+      windowId,
+    });
+    // TODO(robwu): Rework this to use the Extension:ExtensionViewLoaded message
+    // to detect loads and so on. And definitely move this content logic inside
+    // a file in the child process.
 
-    readyPromise = readyPromise.then(() => {
-      let mm = this.browser.messageManager;
+    let initBrowser = browser => {
+      let mm = browser.messageManager;
       mm.addMessageListener("DOMTitleChanged", this);
       mm.addMessageListener("Extension:BrowserBackgroundChanged", this);
       mm.addMessageListener("Extension:BrowserContentLoaded", this);
       mm.addMessageListener("Extension:BrowserResized", this);
       mm.addMessageListener("Extension:DOMWindowClose", this, true);
-      return this.browser;
-    });
+    };
 
     if (!popupURL) {
-      return readyPromise;
+      initBrowser(this.browser);
+      return this.browser;
     }
 
-    return readyPromise.then(() => {
+    return promiseEvent(this.browser, "load").then(() => {
+      initBrowser(this.browser);
+
       let mm = this.browser.messageManager;
 
       mm.loadFrameScript(
         "chrome://extensions/content/ext-browser-content.js", false);
 
       mm.sendAsyncMessage("Extension:InitBrowser", {
         allowScriptsToClose: true,
         fixedWidth: this.fixedWidth,
         maxWidth: 800,
         maxHeight: 600,
         stylesheets: this.STYLESHEETS,
       });
 
-      this.browser.loadURI(popupURL);
+      this.browser.setAttribute("src", popupURL);
     });
   }
 
   resizeBrowser({width, height, detail}) {
     if (this.fixedWidth) {
       // Figure out how much extra space we have on the side of the panel
       // opposite the arrow.
       let side = this.panel.getAttribute("side") == "top" ? "bottom" : "top";
@@ -375,18 +369,18 @@ class PanelPopup extends BasePopup {
 
   destroy() {
     super.destroy();
     this.viewNode.remove();
   }
 
   closePopup() {
     promisePopupShown(this.viewNode).then(() => {
-      // Make sure we're not already destroyed, or removed from the DOM.
-      if (this.viewNode && this.viewNode.hidePopup) {
+      // Make sure we're not already destroyed.
+      if (this.viewNode) {
         this.viewNode.hidePopup();
       }
     });
   }
 }
 
 class ViewPopup extends BasePopup {
   constructor(extension, window, popupURL, browserStyle, fixedWidth) {
@@ -465,17 +459,17 @@ class ViewPopup extends BasePopup {
       let screenBottom = win.screen.availTop + win.screen.availHeight;
       this.extraHeight = {
         bottom: Math.max(0, screenBottom - popupBottom),
         top:  Math.max(0, popupTop - win.screen.availTop),
       };
 
       // Create a new browser in the real popup.
       let browser = this.browser;
-      yield this.createBrowser(this.viewNode);
+      this.createBrowser(this.viewNode);
 
       this.browser.swapDocShells(browser);
       this.destroyBrowser(browser);
 
       this.ignoreResizes = false;
       if (this.dimensions) {
         this.resizeBrowser(this.dimensions);
       }
@@ -502,18 +496,19 @@ class ViewPopup extends BasePopup {
     });
   }
 
   get DESTROY_EVENT() {
     return "ViewHiding";
   }
 
   closePopup() {
-    CustomizableUI.hidePanelForNode(this.viewNode);
-    if (!this.attached) {
+    if (this.attached) {
+      CustomizableUI.hidePanelForNode(this.viewNode);
+    } else {
       this.destroy();
     }
   }
 }
 
 Object.assign(global, {PanelPopup, ViewPopup});
 
 // Manages tab-specific context data, and dispatching tab select events
@@ -689,56 +684,31 @@ ExtensionTabManager.prototype = {
 
   getTabs(window) {
     return Array.from(window.gBrowser.tabs)
                 .filter(tab => !tab.closing)
                 .map(tab => this.convert(tab));
   },
 };
 
-function getBrowserInfo(browser) {
-  if (!browser.ownerGlobal.gBrowser) {
-    // When we're loaded into a <browser> inside about:addons, we need to go up
-    // one more level.
-    browser = browser.ownerGlobal.QueryInterface(Ci.nsIInterfaceRequestor)
-                     .getInterface(Ci.nsIDocShell)
-                     .chromeEventHandler;
-
-    if (!browser) {
-      return {};
-    }
-  }
-
-  let result = {};
-
-  let window = browser.ownerGlobal;
-  if (window.gBrowser) {
-    let tab = window.gBrowser.getTabForBrowser(browser);
-    if (tab) {
-      result.tabId = TabManager.getId(tab);
-    }
-
-    result.windowId = WindowManager.getId(window);
-  }
-
-  return result;
-}
-global.getBrowserInfo = getBrowserInfo;
-
 // Sends the tab and windowId upon request. This is primarily used to support
 // the synchronous `browser.extension.getViews` API.
 let onGetTabAndWindowId = {
   receiveMessage({name, target, sync}) {
-    let result = getBrowserInfo(target);
-
-    if (result.tabId) {
+    let {gBrowser} = target.ownerGlobal;
+    let tab = gBrowser && gBrowser.getTabForBrowser(target);
+    if (tab) {
+      let reply = {
+        tabId: TabManager.getId(tab),
+        windowId: WindowManager.getId(tab.ownerGlobal),
+      };
       if (sync) {
-        return result;
+        return reply;
       }
-      target.messageManager.sendAsyncMessage("Extension:SetTabAndWindowId", result);
+      target.messageManager.sendAsyncMessage("Extension:SetTabAndWindowId", reply);
     }
   },
 };
 /* eslint-disable mozilla/balanced-listeners */
 Services.mm.addMessageListener("Extension:GetTabAndWindowId", onGetTabAndWindowId);
 /* eslint-enable mozilla/balanced-listeners */
 
 
--- a/browser/components/extensions/moz.build
+++ b/browser/components/extensions/moz.build
@@ -7,15 +7,11 @@
 JAR_MANIFESTS += ['jar.mn']
 
 EXTRA_COMPONENTS += [
     'extensions-browser.manifest',
 ]
 
 DIRS += ['schemas']
 
-BROWSER_CHROME_MANIFESTS += [
-    'test/browser/browser-remote.ini',
-    'test/browser/browser.ini',
-]
-
+BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
 MOCHITEST_MANIFESTS += ['test/mochitest/mochitest.ini']
 XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell/xpcshell.ini']
deleted file mode 100644
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ /dev/null
@@ -1,104 +0,0 @@
-[DEFAULT]
-support-files =
-  head.js
-  head_pageAction.js
-  head_sessions.js
-  context.html
-  ctxmenu-image.png
-  context_tabs_onUpdated_page.html
-  context_tabs_onUpdated_iframe.html
-  file_popup_api_injection_a.html
-  file_popup_api_injection_b.html
-  file_iframe_document.html
-  file_iframe_document.sjs
-  file_bypass_cache.sjs
-  file_language_fr_en.html
-  file_language_ja.html
-  file_language_tlh.html
-  file_dummy.html
-  searchSuggestionEngine.xml
-  searchSuggestionEngine.sjs
-
-[browser_ext_browserAction_context.js]
-[browser_ext_browserAction_disabled.js]
-[browser_ext_browserAction_pageAction_icon.js]
-[browser_ext_browserAction_pageAction_icon_permissions.js]
-[browser_ext_browserAction_popup.js]
-[browser_ext_browserAction_popup_resize.js]
-[browser_ext_browserAction_simple.js]
-[browser_ext_commands_execute_browser_action.js]
-[browser_ext_commands_execute_page_action.js]
-[browser_ext_commands_getAll.js]
-[browser_ext_commands_onCommand.js]
-[browser_ext_contentscript_connect.js]
-[browser_ext_contextMenus.js]
-[browser_ext_contextMenus_checkboxes.js]
-[browser_ext_contextMenus_icons.js]
-[browser_ext_contextMenus_onclick.js]
-[browser_ext_contextMenus_radioGroups.js]
-[browser_ext_contextMenus_uninstall.js]
-[browser_ext_contextMenus_urlPatterns.js]
-[browser_ext_currentWindow.js]
-[browser_ext_getViews.js]
-[browser_ext_incognito_popup.js]
-[browser_ext_lastError.js]
-[browser_ext_optionsPage_privileges.js]
-[browser_ext_pageAction_context.js]
-[browser_ext_pageAction_popup.js]
-[browser_ext_pageAction_popup_resize.js]
-[browser_ext_pageAction_simple.js]
-[browser_ext_pageAction_title.js]
-[browser_ext_popup_api_injection.js]
-[browser_ext_popup_background.js]
-[browser_ext_popup_corners.js]
-[browser_ext_popup_sendMessage.js]
-[browser_ext_popup_shutdown.js]
-[browser_ext_runtime_openOptionsPage.js]
-[browser_ext_runtime_openOptionsPage_uninstall.js]
-[browser_ext_runtime_setUninstallURL.js]
-[browser_ext_sessions_getRecentlyClosed.js]
-[browser_ext_sessions_getRecentlyClosed_private.js]
-[browser_ext_sessions_restore.js]
-[browser_ext_simple.js]
-[browser_ext_tab_runtimeConnect.js]
-[browser_ext_tabs_audio.js]
-[browser_ext_tabs_captureVisibleTab.js]
-[browser_ext_tabs_create.js]
-[browser_ext_tabs_create_invalid_url.js]
-[browser_ext_tabs_detectLanguage.js]
-[browser_ext_tabs_duplicate.js]
-[browser_ext_tabs_events.js]
-[browser_ext_tabs_executeScript.js]
-[browser_ext_tabs_executeScript_good.js]
-[browser_ext_tabs_executeScript_bad.js]
-[browser_ext_tabs_executeScript_runAt.js]
-[browser_ext_tabs_getCurrent.js]
-[browser_ext_tabs_insertCSS.js]
-[browser_ext_tabs_removeCSS.js]
-[browser_ext_tabs_move.js]
-[browser_ext_tabs_move_window.js]
-[browser_ext_tabs_move_window_multiple.js]
-[browser_ext_tabs_move_window_pinned.js]
-[browser_ext_tabs_onHighlighted.js]
-[browser_ext_tabs_onUpdated.js]
-[browser_ext_tabs_query.js]
-[browser_ext_tabs_reload.js]
-[browser_ext_tabs_reload_bypass_cache.js]
-[browser_ext_tabs_sendMessage.js]
-[browser_ext_tabs_cookieStoreId.js]
-[browser_ext_tabs_update.js]
-[browser_ext_tabs_zoom.js]
-[browser_ext_tabs_update_url.js]
-[browser_ext_topwindowid.js]
-[browser_ext_webNavigation_frameId0.js]
-[browser_ext_webNavigation_getFrames.js]
-[browser_ext_windows.js]
-[browser_ext_windows_create.js]
-tags = fullscreen
-[browser_ext_windows_create_params.js]
-[browser_ext_windows_create_tabId.js]
-[browser_ext_windows_create_url.js]
-[browser_ext_windows_size.js]
-skip-if = os == 'mac' # Fails when windows are randomly opened in fullscreen mode
-[browser_ext_windows_update.js]
-tags = fullscreen
deleted file mode 100644
--- a/browser/components/extensions/test/browser/browser-remote.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-[DEFAULT]
-# This is a horrible hack:
-# In order to run tests under two configurations, we create two browser test
-# manifests, and include a manifest with a common set of tests from each. In
-# order to detect which manifest we're running from, we install the tests listed
-# in this manifest to the sub-directory "test-oop-extensions", and then check
-# whether we're running from that directory from head.js
-install-to-subdir = test-oop-extensions
-tags = webextensions remote-webextensions
-skip-if = !e10s
-
-[include:browser-common.ini]
--- a/browser/components/extensions/test/browser/browser.ini
+++ b/browser/components/extensions/test/browser/browser.ini
@@ -1,12 +1,111 @@
 [DEFAULT]
-tags = webextensions in-process-webextensions
+support-files =
+  head.js
+  head_pageAction.js
+  head_sessions.js
+  context.html
+  ctxmenu-image.png
+  context_tabs_onUpdated_page.html
+  context_tabs_onUpdated_iframe.html
+  file_popup_api_injection_a.html
+  file_popup_api_injection_b.html
+  file_iframe_document.html
+  file_iframe_document.sjs
+  file_bypass_cache.sjs
+  file_language_fr_en.html
+  file_language_ja.html
+  file_language_tlh.html
+  file_dummy.html
+  searchSuggestionEngine.xml
+  searchSuggestionEngine.sjs
+tags = webextensions
 
 
+[browser_ext_browserAction_context.js]
+[browser_ext_browserAction_disabled.js]
+[browser_ext_browserAction_pageAction_icon.js]
+[browser_ext_browserAction_pageAction_icon_permissions.js]
+[browser_ext_browserAction_popup.js]
+[browser_ext_browserAction_popup_resize.js]
+[browser_ext_browserAction_simple.js]
+[browser_ext_commands_execute_browser_action.js]
+[browser_ext_commands_execute_page_action.js]
+[browser_ext_commands_getAll.js]
+[browser_ext_commands_onCommand.js]
+[browser_ext_contentscript_connect.js]
+[browser_ext_contextMenus.js]
+[browser_ext_contextMenus_checkboxes.js]
+[browser_ext_contextMenus_icons.js]
+[browser_ext_contextMenus_onclick.js]
+[browser_ext_contextMenus_radioGroups.js]
+[browser_ext_contextMenus_uninstall.js]
+[browser_ext_contextMenus_urlPatterns.js]
+[browser_ext_currentWindow.js]
+[browser_ext_getViews.js]
+[browser_ext_incognito_popup.js]
+[browser_ext_lastError.js]
 [browser_ext_legacy_extension_context_contentscript.js]
 [browser_ext_omnibox.js]
+[browser_ext_optionsPage_privileges.js]
+[browser_ext_pageAction_context.js]
+[browser_ext_pageAction_popup.js]
+[browser_ext_pageAction_popup_resize.js]
+[browser_ext_pageAction_simple.js]
+[browser_ext_pageAction_title.js]
+[browser_ext_popup_api_injection.js]
+[browser_ext_popup_background.js]
+[browser_ext_popup_corners.js]
+[browser_ext_popup_sendMessage.js]
+[browser_ext_popup_shutdown.js]
+[browser_ext_runtime_openOptionsPage.js]
+[browser_ext_runtime_openOptionsPage_uninstall.js]
+[browser_ext_runtime_setUninstallURL.js]
+[browser_ext_sessions_getRecentlyClosed.js]
+[browser_ext_sessions_getRecentlyClosed_private.js]
+[browser_ext_sessions_restore.js]
+[browser_ext_simple.js]
+[browser_ext_tab_runtimeConnect.js]
+[browser_ext_tabs_audio.js]
+[browser_ext_tabs_captureVisibleTab.js]
+[browser_ext_tabs_create.js]
+[browser_ext_tabs_create_invalid_url.js]
+[browser_ext_tabs_detectLanguage.js]
+[browser_ext_tabs_duplicate.js]
+[browser_ext_tabs_events.js]
+[browser_ext_tabs_executeScript.js]
+[browser_ext_tabs_executeScript_good.js]
+[browser_ext_tabs_executeScript_bad.js]
+[browser_ext_tabs_executeScript_runAt.js]
+[browser_ext_tabs_getCurrent.js]
+[browser_ext_tabs_insertCSS.js]
+[browser_ext_tabs_removeCSS.js]
+[browser_ext_tabs_move.js]
+[browser_ext_tabs_move_window.js]
+[browser_ext_tabs_move_window_multiple.js]
+[browser_ext_tabs_move_window_pinned.js]
+[browser_ext_tabs_onHighlighted.js]
+[browser_ext_tabs_onUpdated.js]
+[browser_ext_tabs_query.js]
+[browser_ext_tabs_reload.js]
+[browser_ext_tabs_reload_bypass_cache.js]
+[browser_ext_tabs_sendMessage.js]
+[browser_ext_tabs_cookieStoreId.js]
+[browser_ext_tabs_update.js]
+[browser_ext_tabs_zoom.js]
+[browser_ext_tabs_update_url.js]
+[browser_ext_topwindowid.js]
+[browser_ext_webNavigation_frameId0.js]
+[browser_ext_webNavigation_getFrames.js]
 [browser_ext_webNavigation_urlbar_transitions.js]
+[browser_ext_windows.js]
 [browser_ext_windows_allowScriptsToClose.js]
+[browser_ext_windows_create.js]
+tags = fullscreen
+[browser_ext_windows_create_params.js]
+[browser_ext_windows_create_tabId.js]
+[browser_ext_windows_create_url.js]
 [browser_ext_windows_events.js]
-
-[include:browser-common.ini]
-[parent:browser-common.ini]
+[browser_ext_windows_size.js]
+skip-if = os == 'mac' # Fails when windows are randomly opened in fullscreen mode
+[browser_ext_windows_update.js]
+tags = fullscreen
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_popup.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_popup.js
@@ -77,17 +77,17 @@ function* testInArea(area) {
           },
           () => {
             browser.test.log(`Call triggerAction again. Expect popup "a" again.`);
             sendClick({expectEvent: false, expectPopup: "a"}, "trigger-action");
           },
           () => {
             browser.test.log(`Set popup to "c" and click browser action. Expect popup "c".`);
             browser.browserAction.setPopup({popup: "popup-c.html"});
-            sendClick({expectEvent: false, expectPopup: "c", waitUntilClosed: true});
+            sendClick({expectEvent: false, expectPopup: "c", closePopup: false});
           },
           () => {
             browser.test.log(`Set popup to "b" and click browser action. Expect popup "b".`);
             browser.browserAction.setPopup({popup: "popup-b.html"});
             sendClick({expectEvent: false, expectPopup: "b"});
           },
           () => {
             browser.test.log(`Click browser action again, expect popup "b".`);
@@ -115,17 +115,17 @@ function* testInArea(area) {
             browser.test.log(`Tell popup "a" to call window.close(). Expect popup closed.`);
             browser.test.sendMessage("next-test", {closePopupUsingWindow: true});
           },
         ];
 
         let expect = {};
         sendClick = ({expectEvent, expectPopup, runNextTest, waitUntilClosed, closePopup}, message = "send-click") => {
           if (closePopup == undefined) {
-            closePopup = !expectEvent;
+            closePopup = true;
           }
 
           expect = {event: expectEvent, popup: expectPopup, runNextTest, waitUntilClosed, closePopup};
           browser.test.sendMessage(message);
         };
 
         browser.runtime.onMessage.addListener(msg => {
           if (msg == "close-popup-using-window.close") {
@@ -185,36 +185,30 @@ function* testInArea(area) {
 
   let widget;
   extension.onMessage("next-test", Task.async(function* (expecting = {}) {
     if (!widget) {
       widget = getBrowserActionWidget(extension);
       CustomizableUI.addWidgetToArea(widget.id, area);
     }
     if (expecting.waitUntilClosed) {
-      yield new Promise(resolve => setTimeout(resolve, 0));
-
       let panel = getBrowserActionPopup(extension);
       if (panel && panel.state != "closed") {
         yield promisePopupHidden(panel);
       }
     } else if (expecting.closePopupUsingWindow) {
       let panel = getBrowserActionPopup(extension);
       ok(panel, "Expect panel to exist");
       yield promisePopupShown(panel);
 
       extension.sendMessage("close-popup-using-window.close");
 
       yield promisePopupHidden(panel);
       ok(true, "Panel is closed");
     } else if (expecting.closePopup) {
-      if (!getBrowserActionPopup(extension)) {
-        yield awaitExtensionPanel(extension);
-      }
-
       yield closeBrowserAction(extension);
     }
 
     extension.sendMessage("next-test");
   }));
 
   yield Promise.all([extension.startup(), extension.awaitFinish("browseraction-tests-done")]);
 
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_popup_resize.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_popup_resize.js
@@ -19,17 +19,17 @@ add_task(function* testBrowserActionPopu
 
     files: {
       "popup.html": '<!DOCTYPE html><html><head><meta charset="utf-8"></head></html>',
     },
   });
 
   yield extension.startup();
 
-  let browser = yield openPanel(extension, undefined, true);
+  let browser = yield openPanel(extension);
 
   function* checkSize(expected) {
     let dims = yield promiseContentDimensions(browser);
 
     is(dims.window.innerHeight, expected, `Panel window should be ${expected}px tall`);
     is(dims.body.clientHeight, dims.body.scrollHeight,
       "Panel body should be tall enough to fit its contents");
 
--- a/browser/components/extensions/test/browser/browser_ext_commands_execute_browser_action.js
+++ b/browser/components/extensions/test/browser/browser_ext_commands_execute_browser_action.js
@@ -77,20 +77,16 @@ function* testExecuteBrowserActionWithOp
     let widget = getBrowserActionWidget(extension);
     CustomizableUI.addWidgetToArea(widget.id, options.inArea);
   }
 
   extension.sendMessage("withPopup", options.withPopup);
 
   if (options.withPopup) {
     yield extension.awaitFinish("execute-browser-action-popup-opened");
-
-    if (!getBrowserActionPopup(extension)) {
-      yield awaitExtensionPanel(extension);
-    }
     yield closeBrowserAction(extension);
   } else {
     yield extension.awaitFinish("execute-browser-action-on-clicked-fired");
   }
   yield extension.unload();
 }
 
 add_task(function* test_execute_browser_action_with_popup() {
--- a/browser/components/extensions/test/browser/browser_ext_pageAction_popup_resize.js
+++ b/browser/components/extensions/test/browser/browser_ext_pageAction_popup_resize.js
@@ -34,27 +34,18 @@ add_task(function* testPageActionPopupRe
 
   yield extension.startup();
   yield extension.awaitMessage("action-shown");
 
   clickPageAction(extension, window);
 
   browser = yield awaitExtensionPanel(extension);
 
-  function* waitForSize(size) {
+  function* checkSize(expected) {
     let dims = yield promiseContentDimensions(browser);
-    for (let i = 0; i < 100 && dims.window.innerWidth < size; i++) {
-      yield delay(50);
-      dims = yield promiseContentDimensions(browser);
-    }
-    return dims;
-  }
-
-  function* checkSize(expected) {
-    let dims = yield waitForSize(expected);
     let {body, root} = dims;
 
     is(dims.window.innerHeight, expected, `Panel window should be ${expected}px tall`);
     is(body.clientHeight, body.scrollHeight,
       "Panel body should be tall enough to fit its contents");
     is(root.clientHeight, root.scrollHeight,
       "Panel root should be tall enough to fit its contents");
 
@@ -80,19 +71,26 @@ add_task(function* testPageActionPopupRe
 
   for (let size of sizes) {
     yield alterContent(browser, setSize, size);
     yield checkSize(size);
   }
 
   yield alterContent(browser, setSize, 1400);
 
-  let dims = yield waitForSize(800);
+  let dims = yield promiseContentDimensions(browser);
   let {body, root} = dims;
 
+  if (AppConstants.platform == "win") {
+    while (dims.window.innerWidth < 800) {
+      yield delay(50);
+      dims = yield promiseContentDimensions(browser);
+    }
+  }
+
   is(dims.window.innerWidth, 800, "Panel window width");
   ok(body.clientWidth <= 800, `Panel body width ${body.clientWidth} is less than 800`);
   is(body.scrollWidth, 1400, "Panel body scroll width");
 
   is(dims.window.innerHeight, 600, "Panel window height");
   ok(root.clientHeight <= 600, `Panel root height (${root.clientHeight}px) is less than 600px`);
   is(root.scrollHeight, 1400, "Panel root scroll height");
 
--- a/browser/components/extensions/test/browser/browser_ext_popup_api_injection.js
+++ b/browser/components/extensions/test/browser/browser_ext_popup_api_injection.js
@@ -56,17 +56,17 @@ add_task(function* testPageActionPopup()
   yield extension.awaitMessage("ready");
 
 
   // Check that unprivileged documents don't get the API.
   // BrowserAction:
   let awaitMessage = promiseConsoleMessage(/WebExt Privilege Escalation: BrowserAction/);
   SimpleTest.expectUncaughtException();
   yield clickBrowserAction(extension);
-  yield awaitExtensionPanel(extension);
+  yield promisePopupShown(getBrowserActionPopup(extension));
 
   let message = yield awaitMessage;
   ok(message.includes("WebExt Privilege Escalation: BrowserAction: typeof(browser) = undefined"),
      `No BrowserAction API injection`);
 
   yield closeBrowserAction(extension);
 
   // PageAction
@@ -84,18 +84,18 @@ add_task(function* testPageActionPopup()
 
 
   // Check that privileged documents *do* get the API.
   extension.sendMessage("next");
   yield extension.awaitMessage("ok");
 
 
   yield clickBrowserAction(extension);
-  yield awaitExtensionPanel(extension);
   yield extension.awaitMessage("from-popup-a");
+  yield promisePopupShown(getBrowserActionPopup(extension));
   yield closeBrowserAction(extension);
 
   yield clickPageAction(extension);
   yield extension.awaitMessage("from-popup-b");
   yield closePageAction(extension);
 
   yield extension.unload();
 });
--- a/browser/components/extensions/test/browser/browser_ext_tabs_events.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_events.js
@@ -1,54 +1,39 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 add_task(function* testTabEvents() {
   async function background() {
     let events = [];
-    let eventPromise;
-    let checkEvents = () => {
-      if (eventPromise && events.length >= eventPromise.names.length) {
-        eventPromise.resolve();
-      }
-    };
-
     browser.tabs.onCreated.addListener(tab => {
       events.push({type: "onCreated", tab});
-      checkEvents();
     });
 
     browser.tabs.onAttached.addListener((tabId, info) => {
       events.push(Object.assign({type: "onAttached", tabId}, info));
-      checkEvents();
     });
 
     browser.tabs.onDetached.addListener((tabId, info) => {
       events.push(Object.assign({type: "onDetached", tabId}, info));
-      checkEvents();
     });
 
     browser.tabs.onRemoved.addListener((tabId, info) => {
       events.push(Object.assign({type: "onRemoved", tabId}, info));
-      checkEvents();
     });
 
     browser.tabs.onMoved.addListener((tabId, info) => {
       events.push(Object.assign({type: "onMoved", tabId}, info));
-      checkEvents();
     });
 
     async function expectEvents(names) {
       browser.test.log(`Expecting events: ${names.join(", ")}`);
 
-      await new Promise(resolve => {
-        eventPromise = {names, resolve};
-        checkEvents();
-      });
+      await new Promise(resolve => setTimeout(resolve, 0));
 
       browser.test.assertEq(names.length, events.length, "Got expected number of events");
       for (let [i, name] of names.entries()) {
         browser.test.assertEq(name, i in events && events[i].type,
                               `Got expected ${name} event`);
       }
       return events.splice(0);
     }
--- a/browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js
@@ -1,14 +1,13 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 add_task(function* testExecuteScript() {
-  let {ExtensionManagement} = Cu.import("resource://gre/modules/ExtensionManagement.jsm", {});
   let {MessageChannel} = Cu.import("resource://gre/modules/MessageChannel.jsm", {});
 
   function countMM(messageManagerMap) {
     let count = 0;
     // List of permanent message managers in the main process. We should not
     // count them in the test because MessageChannel unsubscribes when the
     // message manager closes, which never happens to these, of course.
     let globalMMs = [
@@ -245,13 +244,11 @@ add_task(function* testExecuteScript() {
 
   yield extension.unload();
 
   yield BrowserTestUtils.removeTab(tab);
 
   // Make sure that we're not holding on to references to closed message
   // managers.
   is(countMM(MessageChannel.messageManagers), messageManagersSize, "Message manager count");
-  if (!ExtensionManagement.useRemoteWebExtensions) {
-    is(countMM(MessageChannel.responseManagers), responseManagersSize, "Response manager count");
-  }
+  is(countMM(MessageChannel.responseManagers), responseManagersSize, "Response manager count");
   is(MessageChannel.pendingResponses.size, 0, "Pending response count");
 });
--- a/browser/components/extensions/test/browser/head.js
+++ b/browser/components/extensions/test/browser/head.js
@@ -13,29 +13,16 @@
  *          imageBuffer getListStyleImage getPanelForNode
  *          awaitExtensionPanel awaitPopupResize
  *          promiseContentDimensions alterContent
  */
 
 var {AppConstants} = Cu.import("resource://gre/modules/AppConstants.jsm");
 var {CustomizableUI} = Cu.import("resource:///modules/CustomizableUI.jsm");
 
-// We run tests under two different configurations, from browser.ini and
-// browser-remote.ini. When running from browser-remote.ini, the tests are
-// copied to the sub-directory "test-oop-extensions", which we detect here, and
-// use to select our configuration.
-if (gTestPath.includes("test-oop-extensions")) {
-  add_task(() => {
-    return SpecialPowers.pushPrefEnv({set: [
-      ["dom.ipc.processCount", 1],
-      ["extensions.webextensions.remote", true],
-    ]});
-  });
-}
-
 // Bug 1239884: Our tests occasionally hit a long GC pause at unpredictable
 // times in debug builds, which results in intermittent timeouts. Until we have
 // a better solution, we force a GC after certain strategic tests, which tend to
 // accumulate a high number of unreaped windows.
 function forceGC() {
   if (AppConstants.DEBUG) {
     Cu.forceGC();
   }
@@ -140,29 +127,29 @@ function getPanelForNode(node) {
   while (node.localName != "panel") {
     node = node.parentNode;
   }
   return node;
 }
 
 var awaitBrowserLoaded = browser => ContentTask.spawn(browser, null, () => {
   if (content.document.readyState !== "complete") {
-    return ContentTaskUtils.waitForEvent(this, "load", true).then(() => {});
+    return ContentTaskUtils.waitForEvent(content, "load").then(() => {});
   }
 });
 
 var awaitExtensionPanel = Task.async(function* (extension, win = window, awaitLoad = true) {
   let {originalTarget: browser} = yield BrowserTestUtils.waitForEvent(
     win.document, "WebExtPopupLoaded", true,
     event => event.detail.extension.id === extension.id);
 
   yield Promise.all([
     promisePopupShown(getPanelForNode(browser)),
 
-    awaitLoad && awaitBrowserLoaded(browser, awaitLoad),
+    awaitLoad && awaitBrowserLoaded(browser),
   ]);
 
   return browser;
 });
 
 function getBrowserActionWidget(extension) {
   return CustomizableUI.getWidget(makeWidgetId(extension.id) + "-browser-action");
 }
--- a/browser/modules/E10SUtils.jsm
+++ b/browser/modules/E10SUtils.jsm
@@ -4,20 +4,16 @@
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["E10SUtils"];
 
 const {interfaces: Ci, utils: Cu, classes: Cc} = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyPreferenceGetter(this, "useRemoteWebExtensions",
-                                      "extensions.webextensions.remote", false);
 
 function getAboutModule(aURL) {
   // Needs to match NS_GetAboutModuleName
   let moduleName = aURL.path.replace(/[#?].*/, "").toLowerCase();
   let contract = "@mozilla.org/network/protocol/about;1?what=" + moduleName;
   try {
     return Cc[contract].getService(Ci.nsIAboutModule);
   }
@@ -69,18 +65,18 @@ this.E10SUtils = {
         let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].
                         getService(Ci.nsIXULChromeRegistry);
         canLoadRemote = chromeReg.canLoadURLRemotely(url);
         mustLoadRemote = chromeReg.mustLoadURLRemotely(url);
       }
     }
 
     if (aURL.startsWith("moz-extension:")) {
-      canLoadRemote = useRemoteWebExtensions;
-      mustLoadRemote = useRemoteWebExtensions;
+      canLoadRemote = false;
+      mustLoadRemote = false;
     }
 
     if (aURL.startsWith("view-source:")) {
       return this.canLoadURIInProcess(aURL.substr("view-source:".length), aProcess);
     }
 
     if (mustLoadRemote)
       return processIsRemote;
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -2574,33 +2574,17 @@ nsFrameLoader::TryRemoteBrowser()
       openingTab->Manager() &&
       openingTab->Manager()->IsContentParent()) {
     openerContentParent = openingTab->Manager()->AsContentParent();
   }
 
   // <iframe mozbrowser> gets to skip these checks.
   if (!OwnerIsMozBrowserFrame()) {
     if (parentDocShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
-      // Allow about:addon an exception to this rule so it can load remote
-      // extension options pages.
-      //
-      // Note that the new frame's message manager will not be a child of the
-      // chrome window message manager, and, the values of window.top and
-      // window.parent will be different than they would be for a non-remote
-      // frame.
-      nsCOMPtr<nsIWebNavigation> parentWebNav;
-      nsCOMPtr<nsIURI> aboutAddons;
-      nsCOMPtr<nsIURI> parentURI;
-      bool equals;
-      if (!((parentWebNav = do_GetInterface(parentDocShell)) &&
-            NS_SUCCEEDED(NS_NewURI(getter_AddRefs(aboutAddons), "about:addons")) &&
-            NS_SUCCEEDED(parentWebNav->GetCurrentURI(getter_AddRefs(parentURI))) &&
-            NS_SUCCEEDED(parentURI->EqualsExceptRef(aboutAddons, &equals)) && equals)) {
-        return false;
-      }
+      return false;
     }
 
     if (!mOwnerContent->IsXULElement()) {
       return false;
     }
 
     nsAutoString value;
     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value);
--- a/mobile/android/chrome/content/browser.css
+++ b/mobile/android/chrome/content/browser.css
@@ -1,4 +1,7 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+browser[remote="true"] {
+  -moz-binding: url("chrome://global/content/bindings/remote-browser.xml#remote-browser");
+}
\ No newline at end of file
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4703,17 +4703,16 @@ pref("extensions.alwaysUnpack", false);
 pref("extensions.minCompatiblePlatformVersion", "2.0");
 pref("extensions.webExtensionsMinPlatformVersion", "42.0a1");
 
 // Other webextensions prefs
 pref("extensions.webextensions.keepStorageOnUninstall", false);
 pref("extensions.webextensions.keepUuidOnUninstall", false);
 // Redirect basedomain used by identity api
 pref("extensions.webextensions.identity.redirectDomain", "extensions.allizom.org");
-pref("extensions.webextensions.remote", false);
 
 pref("network.buffer.cache.count", 24);
 pref("network.buffer.cache.size",  32768);
 
 // Desktop Notification
 pref("notification.feature.enabled", false);
 
 // Web Notification
--- a/python/mozbuild/mozbuild/testing.py
+++ b/python/mozbuild/mozbuild/testing.py
@@ -60,27 +60,21 @@ class TestMetadata(object):
             test_data = pickle.load(fh)
         defaults = None
         if test_defaults:
             with open(test_defaults, 'rb') as fh:
                 defaults = pickle.load(fh)
         for path, tests in test_data.items():
             for metadata in tests:
                 if defaults:
-                    defaults_manifests = [metadata['manifest']]
-
-                    ancestor_manifest = metadata.get('ancestor-manifest')
-                    if ancestor_manifest:
-                        defaults_manifests.append(ancestor_manifest)
-
-                    for manifest in defaults_manifests:
-                        manifest_defaults = defaults.get(manifest)
-                        if manifest_defaults:
-                            metadata = manifestparser.combine_fields(manifest_defaults,
-                                                                     metadata)
+                    manifest = metadata['manifest']
+                    manifest_defaults = defaults.get(manifest)
+                    if manifest_defaults:
+                        metadata = manifestparser.combine_fields(manifest_defaults,
+                                                                 metadata)
                 self._tests_by_path[path].append(metadata)
                 self._test_dirs.add(os.path.dirname(path))
                 flavor = metadata.get('flavor')
                 self._tests_by_flavor[flavor].add(path)
 
     def tests_with_flavor(self, flavor):
         """Obtain all tests having the specified flavor.
 
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -21,20 +21,16 @@ const Cc = Components.classes;
 const Cu = Components.utils;
 const Cr = Components.results;
 
 Cu.importGlobalProperties(["TextEncoder"]);
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
-/* globals processCount */
-
-XPCOMUtils.defineLazyPreferenceGetter(this, "processCount", "dom.ipc.processCount");
-
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
                                   "resource://gre/modules/AppConstants.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionAPIs",
                                   "resource://gre/modules/ExtensionAPI.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionStorage",
                                   "resource://gre/modules/ExtensionStorage.jsm");
@@ -587,22 +583,16 @@ this.Extension = class extends Extension
       Services.obs.addObserver(this, "xpcom-shutdown", false);
       this.cleanupFile = addonData.cleanupFile || null;
       delete addonData.cleanupFile;
     }
 
     this.addonData = addonData;
     this.startupReason = startupReason;
 
-    this.remote = ExtensionManagement.useRemoteWebExtensions;
-
-    if (this.remote && processCount !== 1) {
-      throw new Error("Out-of-process WebExtensions are not supported with multiple child processes");
-    }
-
     this.id = addonData.id;
     this.baseURI = NetUtil.newURI(this.getURL("")).QueryInterface(Ci.nsIURL);
     this.principal = this.createPrincipal();
 
     this.onStartup = null;
 
     this.hasShutdown = false;
     this.onShutdown = new Set();
@@ -611,27 +601,16 @@ this.Extension = class extends Extension
 
     this.apis = [];
     this.whiteListedHosts = null;
     this.webAccessibleResources = null;
 
     this.emitter = new EventEmitter();
   }
 
-  get parentMessageManager() {
-    if (this.remote) {
-      // We currently run extensions in the normal web content process. Since
-      // we currently only support remote extensions in single-child e10s,
-      // child 0 is always the current process, and child 1 is always the
-      // remote extension process.
-      return Services.ppmm.getChildAt(1);
-    }
-    return Services.ppmm.getChildAt(0);
-  }
-
   static set browserUpdated(updated) {
     _browserUpdated = updated;
   }
 
   static get browserUpdated() {
     return _browserUpdated;
   }
 
@@ -722,45 +701,25 @@ this.Extension = class extends Extension
       localeData: this.localeData.serialize(),
       permissions: this.permissions,
       principal: this.principal,
     };
   }
 
   broadcast(msg, data) {
     return new Promise(resolve => {
-      let {ppmm} = Services;
-      let children = new Set();
-      for (let i = 0; i < ppmm.childCount; i++) {
-        children.add(ppmm.getChildAt(i));
-      }
-
-      let maybeResolve;
-      function listener(data) {
-        children.delete(data.target);
-        maybeResolve();
-      }
-      function observer(subject, topic, data) {
-        children.delete(subject);
-        maybeResolve();
-      }
-
-      maybeResolve = () => {
-        if (children.size === 0) {
-          ppmm.removeMessageListener(msg + "Complete", listener);
-          Services.obs.removeObserver(observer, "message-manager-close");
-          Services.obs.removeObserver(observer, "message-manager-disconnect");
+      let count = Services.ppmm.childCount;
+      Services.ppmm.addMessageListener(msg + "Complete", function listener() {
+        count--;
+        if (count == 0) {
+          Services.ppmm.removeMessageListener(msg + "Complete", listener);
           resolve();
         }
-      };
-      ppmm.addMessageListener(msg + "Complete", listener);
-      Services.obs.addObserver(observer, "message-manager-close", false);
-      Services.obs.addObserver(observer, "message-manager-disconnect", false);
-
-      ppmm.broadcastAsyncMessage(msg, data);
+      });
+      Services.ppmm.broadcastAsyncMessage(msg, data);
     });
   }
 
   runManifest(manifest) {
     // Strip leading slashes from web_accessible_resources.
     let strippedWebAccessibleResources = [];
     if (manifest.web_accessible_resources) {
       strippedWebAccessibleResources = manifest.web_accessible_resources.map(path => path.replace(/^\/+/, ""));
--- a/toolkit/components/extensions/ExtensionChild.jsm
+++ b/toolkit/components/extensions/ExtensionChild.jsm
@@ -17,18 +17,16 @@ this.EXPORTED_SYMBOLS = ["ExtensionChild
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cu = Components.utils;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "ExtensionManagement",
-                                  "resource://gre/modules/ExtensionManagement.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "MessageChannel",
                                   "resource://gre/modules/MessageChannel.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NativeApp",
                                   "resource://gre/modules/NativeMessaging.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PromiseUtils",
                                   "resource://gre/modules/PromiseUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
                                   "resource://gre/modules/Schemas.jsm");
@@ -43,17 +41,16 @@ const {
   EventManager,
   SingletonEventManager,
   SpreadArgs,
   defineLazyGetter,
   getInnerWindowID,
   getMessageManager,
   getUniqueId,
   injectAPI,
-  promiseEvent,
 } = ExtensionUtils;
 
 const {
   BaseContext,
   LocalAPIImplementation,
   SchemaAPIInterface,
   SchemaAPIManager,
 } = ExtensionCommon;
@@ -729,16 +726,22 @@ class ExtensionPageContextChild extends 
    * @param {string} params.viewType One of "background", "popup" or "tab".
    *     "background" and "tab" are used by `browser.extension.getViews`.
    *     "popup" is only used internally to identify page action and browser
    *     action popups and options_ui pages.
    * @param {number} [params.tabId] This tab's ID, used if viewType is "tab".
    */
   constructor(extension, params) {
     super("addon_child", extension);
+    if (Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_DEFAULT) {
+      // This check is temporary. It should be removed once the proxy creation
+      // is asynchronous.
+      throw new Error("ExtensionPageContextChild cannot be created in child processes");
+    }
+
     let {viewType, uri, contentWindow, tabId} = params;
     this.viewType = viewType;
     this.uri = uri || extension.baseURI;
 
     this.setContentWindow(contentWindow);
 
     // This is the MessageSender property passed to extension.
     // It can be augmented by the "page-open" hook.
@@ -854,24 +857,26 @@ class ContentGlobal {
     // Unless specified otherwise assume that the extension page is in a tab,
     // because the majority of all class instances are going to be a tab. Any
     // special views (background page, extension popup) will immediately send an
     // Extension:InitExtensionView message to change the viewType.
     this.viewType = "tab";
     this.tabId = -1;
     this.windowId = -1;
     this.initialized = false;
-
     this.global.addMessageListener("Extension:InitExtensionView", this);
     this.global.addMessageListener("Extension:SetTabAndWindowId", this);
+
+    this.initialDocuments = new WeakSet();
   }
 
   uninit() {
     this.global.removeMessageListener("Extension:InitExtensionView", this);
     this.global.removeMessageListener("Extension:SetTabAndWindowId", this);
+    this.global.removeEventListener("DOMContentLoaded", this);
   }
 
   ensureInitialized() {
     if (!this.initialized) {
       // Request tab and window ID in case "Extension:InitExtensionView" is not
       // sent (e.g. when `viewType` is "tab").
       let reply = this.global.sendSyncMessage("Extension:GetTabAndWindowId");
       this.handleSetTabAndWindowId(reply[0] || {});
@@ -879,108 +884,118 @@ class ContentGlobal {
     return this;
   }
 
   receiveMessage({name, data}) {
     switch (name) {
       case "Extension:InitExtensionView":
         // The view type is initialized once and then fixed.
         this.global.removeMessageListener("Extension:InitExtensionView", this);
-        this.viewType = data.viewType;
-
-        promiseEvent(this.global, "DOMContentLoaded", true).then(() => {
-          this.global.sendAsyncMessage("Extension:ExtensionViewLoaded");
-        });
-
-        /* FALLTHROUGH */
+        let {viewType, url} = data;
+        this.viewType = viewType;
+        this.global.addEventListener("DOMContentLoaded", this);
+        if (url) {
+          // TODO(robwu): Remove this check. It is only here because the popup
+          // implementation does not always load a URL at the initialization,
+          // and the logic is too complex to fix at once.
+          let {document} = this.global.content;
+          this.initialDocuments.add(document);
+          document.location.replace(url);
+        }
+        /* Falls through to allow these properties to be initialized at once */
       case "Extension:SetTabAndWindowId":
         this.handleSetTabAndWindowId(data);
         break;
     }
   }
 
   handleSetTabAndWindowId(data) {
     let {tabId, windowId} = data;
-
     if (tabId) {
       // Tab IDs are not expected to change.
       if (this.tabId !== -1 && tabId !== this.tabId) {
         throw new Error("Attempted to change a tabId after it was set");
       }
       this.tabId = tabId;
     }
-
     if (windowId !== undefined) {
       // Window IDs may change if a tab is moved to a different location.
       // Note: This is the ID of the browser window for the extension API.
       // Do not confuse it with the innerWindowID of DOMWindows!
       this.windowId = windowId;
     }
     this.initialized = true;
   }
+
+  // "DOMContentLoaded" event.
+  handleEvent(event) {
+    let {document} = this.global.content;
+    if (event.target === document) {
+      // If the document was still being loaded at the time of navigation, then
+      // the DOMContentLoaded event is fired for the old document. Ignore it.
+      if (this.initialDocuments.has(document)) {
+        this.initialDocuments.delete(document);
+        return;
+      }
+      this.global.removeEventListener("DOMContentLoaded", this);
+      this.global.sendAsyncMessage("Extension:ExtensionViewLoaded");
+    }
+  }
 }
 
 ExtensionChild = {
-  ChildAPIManager,
-  Messenger,
-  Port,
-
   // Map<nsIContentFrameMessageManager, ContentGlobal>
   contentGlobals: new Map(),
 
   // Map<innerWindowId, ExtensionPageContextChild>
   extensionContexts: new Map(),
 
   initOnce() {
     // This initializes the default message handler for messages targeted at
     // an addon process, in case the addon process receives a message before
     // its Messenger has been instantiated. For example, if a content script
     // sends a message while there is no background page.
     MessageChannel.setupMessageManagers([Services.cpmm]);
   },
 
   init(global) {
-    if (!ExtensionManagement.isExtensionProcess) {
-      throw new Error("Cannot init extension page global in current process");
-    }
-
     this.contentGlobals.set(global, new ContentGlobal(global));
   },
 
   uninit(global) {
     this.contentGlobals.get(global).uninit();
     this.contentGlobals.delete(global);
   },
 
   /**
    * Create a privileged context at document-element-inserted.
    *
    * @param {BrowserExtensionContent} extension
    *     The extension for which the context should be created.
    * @param {nsIDOMWindow} contentWindow The global of the page.
    */
   createExtensionContext(extension, contentWindow) {
-    if (!ExtensionManagement.isExtensionProcess) {
-      throw new Error("Cannot create an extension page context in current process");
-    }
-
     let windowId = getInnerWindowID(contentWindow);
     let context = this.extensionContexts.get(windowId);
     if (context) {
       if (context.extension !== extension) {
-        throw new Error("A different extension context already exists for this frame");
+        // Oops. This should never happen.
+        Cu.reportError("A different extension context already exists in this frame!");
+      } else {
+        // This should not happen either.
+        Cu.reportError("The extension context was already initialized in this frame.");
       }
-      throw new Error("An extension context was already initialized for this frame");
+      return;
     }
 
-    let mm = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                          .getInterface(Ci.nsIDocShell)
-                          .QueryInterface(Ci.nsIInterfaceRequestor)
-                          .getInterface(Ci.nsIContentFrameMessageManager);
-
+    let mm = contentWindow
+      .QueryInterface(Ci.nsIInterfaceRequestor)
+      .getInterface(Ci.nsIDocShell)
+      .QueryInterface(Ci.nsIInterfaceRequestor)
+      .getInterface(Ci.nsIContentFrameMessageManager);
     let {viewType, tabId} = this.contentGlobals.get(mm).ensureInitialized();
 
     let uri = contentWindow.document.documentURIObject;
 
     context = new ExtensionPageContextChild(extension, {viewType, contentWindow, uri, tabId});
     this.extensionContexts.set(windowId, context);
   },
 
@@ -1001,8 +1016,25 @@ ExtensionChild = {
     for (let [windowId, context] of this.extensionContexts) {
       if (context.extension.id == extensionId) {
         context.shutdown();
         this.extensionContexts.delete(windowId);
       }
     }
   },
 };
+
+// TODO(robwu): Change this condition when addons move to a separate process.
+if (Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_DEFAULT) {
+  Object.keys(ExtensionChild).forEach(function(key) {
+    if (typeof ExtensionChild[key] == "function") {
+      // :/
+      ExtensionChild[key] = () => {};
+    }
+  });
+}
+
+Object.assign(ExtensionChild, {
+  ChildAPIManager,
+  Messenger,
+  Port,
+});
+
--- a/toolkit/components/extensions/ExtensionContent.jsm
+++ b/toolkit/components/extensions/ExtensionContent.jsm
@@ -1020,25 +1020,21 @@ class ExtensionGlobal {
   }
 }
 
 this.ExtensionContent = {
   globals: new Map(),
 
   init(global) {
     this.globals.set(global, new ExtensionGlobal(global));
-    if (ExtensionManagement.isExtensionProcess) {
-      ExtensionChild.init(global);
-    }
+    ExtensionChild.init(global);
   },
 
   uninit(global) {
-    if (ExtensionManagement.isExtensionProcess) {
-      ExtensionChild.uninit(global);
-    }
+    ExtensionChild.uninit(global);
     this.globals.get(global).uninit();
     this.globals.delete(global);
   },
 
   // This helper is exported to be integrated in the devtools RDP actors,
   // that can use it to retrieve the existent WebExtensions ContentScripts
   // of a target window and be able to show the ContentScripts source in the
   // DevTools Debugger panel.
--- a/toolkit/components/extensions/ExtensionManagement.jsm
+++ b/toolkit/components/extensions/ExtensionManagement.jsm
@@ -20,18 +20,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 
 XPCOMUtils.defineLazyGetter(this, "console", () => ExtensionUtils.getConsole());
 
 XPCOMUtils.defineLazyGetter(this, "UUIDMap", () => {
   let {UUIDMap} = Cu.import("resource://gre/modules/Extension.jsm", {});
   return UUIDMap;
 });
 
-var ExtensionManagement;
-
 /*
  * This file should be kept short and simple since it's loaded even
  * when no extensions are running.
  */
 
 // Keep track of frame IDs for content windows. Mostly we can just use
 // the outer window ID as the frame ID. However, the API specifies
 // that top-level windows have a frame ID of 0. So we need to keep
@@ -205,30 +203,27 @@ var Service = {
   // Checks whether a given extension can load this URI (typically via
   // an XML HTTP request). The manifest.json |permissions| directive
   // determines this.
   checkAddonMayLoad(extension, uri) {
     return extension.whiteListedHosts.matchesIgnoringPath(uri);
   },
 
   generateBackgroundPageUrl(extension) {
-    let background_scripts = (extension.manifest.background &&
-                              extension.manifest.background.scripts);
-
+    let background_scripts = extension.manifest.background &&
+      extension.manifest.background.scripts;
     if (!background_scripts) {
       return;
     }
-
-    let html = "<!DOCTYPE html>\n<html>\n<body>\n";
+    let html = "<!DOCTYPE html>\n<body>\n";
     for (let script of background_scripts) {
       script = script.replace(/"/g, "&quot;");
       html += `<script src="${script}"></script>\n`;
     }
     html += "</body>\n</html>\n";
-
     return "data:text/html;charset=utf-8," + encodeURIComponent(html);
   },
 
   // Finds the add-on ID associated with a given moz-extension:// URI.
   // This is used to set the addonId on the originAttributes for the
   // nsIPrincipal attached to the URI.
   extensionURIToAddonID(uri) {
     let uuid = uri.host;
@@ -259,17 +254,19 @@ function getAPILevelForWindow(window, ad
   const {NO_PRIVILEGES, CONTENTSCRIPT_PRIVILEGES, FULL_PRIVILEGES} = API_LEVELS;
 
   // Non WebExtension URLs and WebExtension URLs from a different extension
   // has no access to APIs.
   if (!addonId || getAddonIdForWindow(window) != addonId) {
     return NO_PRIVILEGES;
   }
 
-  if (!ExtensionManagement.isExtensionProcess) {
+  // Extension pages running in the content process always defaults to
+  // "content script API level privileges".
+  if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
     return CONTENTSCRIPT_PRIVILEGES;
   }
 
   let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIDocShell);
 
   // Handling of ExtensionPages running inside sub-frames.
   if (docShell.sameTypeParent) {
@@ -298,22 +295,17 @@ function getAPILevelForWindow(window, ad
     // (see Bug 1214658 for rationale)
     return CONTENTSCRIPT_PRIVILEGES;
   }
 
   // WebExtension URLs loaded into top frames UI could have full API level privileges.
   return FULL_PRIVILEGES;
 }
 
-ExtensionManagement = {
-  get isExtensionProcess() {
-    return (this.useRemoteWebExtensions ||
-            Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_DEFAULT);
-  },
-
+this.ExtensionManagement = {
   startupExtension: Service.startupExtension.bind(Service),
   shutdownExtension: Service.shutdownExtension.bind(Service),
 
   registerAPI: APIs.register.bind(APIs),
   unregisterAPI: APIs.unregister.bind(APIs),
 
   getFrameId: Frames.getId.bind(Frames),
   getParentFrameId: Frames.getParentId.bind(Frames),
@@ -322,11 +314,8 @@ ExtensionManagement = {
 
   // exported API Level Helpers
   getAddonIdForWindow,
   getAPILevelForWindow,
   API_LEVELS,
 
   APIs,
 };
-
-XPCOMUtils.defineLazyPreferenceGetter(ExtensionManagement, "useRemoteWebExtensions",
-                                      "extensions.webextensions.remote", false);
--- a/toolkit/components/extensions/ExtensionParent.jsm
+++ b/toolkit/components/extensions/ExtensionParent.jsm
@@ -101,31 +101,34 @@ let apiManager = new class extends Schem
   }
 }();
 
 // Subscribes to messages related to the extension messaging API and forwards it
 // to the relevant message manager. The "sender" field for the `onMessage` and
 // `onConnect` events are updated if needed.
 ProxyMessenger = {
   _initialized: false,
-
   init() {
     if (this._initialized) {
       return;
     }
     this._initialized = true;
 
+    // TODO(robwu): When addons move to a separate process, we should use the
+    // parent process manager(s) of the addon process(es) instead of the
+    // in-process one.
+    let pipmm = Services.ppmm.getChildAt(0);
     // Listen on the global frame message manager because content scripts send
     // and receive extension messages via their frame.
     // Listen on the parent process message manager because `runtime.connect`
     // and `runtime.sendMessage` requests must be delivered to all frames in an
     // addon process (by the API contract).
     // And legacy addons are not associated with a frame, so that is another
     // reason for having a parent process manager here.
-    let messageManagers = [Services.mm, Services.ppmm];
+    let messageManagers = [Services.mm, pipmm];
 
     MessageChannel.addListener(messageManagers, "Extension:Connect", this);
     MessageChannel.addListener(messageManagers, "Extension:Message", this);
     MessageChannel.addListener(messageManagers, "Extension:Port:Disconnect", this);
     MessageChannel.addListener(messageManagers, "Extension:Port:PostMessage", this);
   },
 
   receiveMessage({target, messageName, channelId, sender, recipient, data, responseType}) {
@@ -139,19 +142,18 @@ ProxyMessenger = {
         let context = ParentAPIManager.getContextById(childId);
         NativeApp.onConnectNative(context, target.messageManager, data.portId, sender, toNativeApp);
         return true;
       }
       // "Extension:Port:Disconnect" and "Extension:Port:PostMessage" for
       // native messages are handled by NativeApp.
       return;
     }
-
     let extension = GlobalManager.extensionMap.get(sender.extensionId);
-    let receiverMM = this.getMessageManagerForRecipient(recipient);
+    let receiverMM = this._getMessageManagerForRecipient(recipient);
     if (!extension || !receiverMM) {
       return Promise.reject({
         result: MessageChannel.RESULT_NO_HANDLER,
         message: "No matching message handler for the given recipient.",
       });
     }
 
     if ((messageName == "Extension:Message" ||
@@ -165,33 +167,33 @@ ProxyMessenger = {
       recipient,
       responseType,
     });
   },
 
   /**
    * @param {object} recipient An object that was passed to
    *     `MessageChannel.sendMessage`.
-   * @param {Extension} extension
    * @returns {object|null} The message manager matching the recipient if found.
    */
-  getMessageManagerForRecipient(recipient) {
-    let {tabId} = recipient;
+  _getMessageManagerForRecipient(recipient) {
+    let {extensionId, tabId} = recipient;
     // tabs.sendMessage / tabs.connect
     if (tabId) {
       // `tabId` being set implies that the tabs API is supported, so we don't
       // need to check whether `TabManager` exists.
       let tab = apiManager.global.TabManager.getTab(tabId, null, null);
       return tab && tab.linkedBrowser.messageManager;
     }
 
     // runtime.sendMessage / runtime.connect
-    let extension = GlobalManager.extensionMap.get(recipient.extensionId);
-    if (extension) {
-      return extension.parentMessageManager;
+    if (extensionId) {
+      // TODO(robwu): map the extensionId to the addon parent process's message
+      // manager when they run in a separate process.
+      return Services.ppmm.getChildAt(0);
     }
 
     return null;
   },
 };
 
 // Responsible for loading extension APIs into the right globals.
 GlobalManager = {
@@ -222,29 +224,16 @@ GlobalManager = {
   _onExtensionBrowser(type, browser) {
     browser.messageManager.loadFrameScript(`data:,
       Components.utils.import("resource://gre/modules/ExtensionContent.jsm");
       ExtensionContent.init(this);
       addEventListener("unload", function() {
         ExtensionContent.uninit(this);
       });
     `, false);
-
-    let viewType = browser.getAttribute("webextension-view-type");
-    if (viewType) {
-      let data = {viewType};
-
-      let {getBrowserInfo} = apiManager.global;
-      if (getBrowserInfo) {
-        Object.assign(data, getBrowserInfo(browser));
-      }
-
-      browser.messageManager.sendAsyncMessage("Extension:InitExtensionView",
-                                              data);
-    }
   },
 
   getExtension(extensionId) {
     return this.extensionMap.get(extensionId);
   },
 
   injectInObject(context, isChromeCompat, dest) {
     apiManager.generateAPIs(context, dest);
@@ -343,23 +332,22 @@ class ExtensionPageContextParent extends
     if (!apiManager.global.WindowManager || this.viewType == "background") {
       return;
     }
     // viewType popup or tab:
     return apiManager.global.WindowManager.getId(this.xulWindow);
   }
 
   get tabId() {
-    let {getBrowserInfo} = apiManager.global;
-
-    if (getBrowserInfo) {
-      // This is currently only available on desktop Firefox.
-      return getBrowserInfo(this.xulBrowser).tabId;
+    if (!apiManager.global.TabManager) {
+      return;  // Not yet supported on Android.
     }
-    return undefined;
+    let {gBrowser} = this.xulBrowser.ownerGlobal;
+    let tab = gBrowser && gBrowser.getTabForBrowser(this.xulBrowser);
+    return tab && apiManager.global.TabManager.getId(tab);
   }
 
   onBrowserChange(browser) {
     super.onBrowserChange(browser);
     this.xulBrowser = browser;
   }
 
   shutdown() {
@@ -433,16 +421,22 @@ ParentAPIManager = {
 
     let extension = GlobalManager.getExtension(extensionId);
     if (!extension) {
       throw new Error(`No WebExtension found with ID ${extensionId}`);
     }
 
     let context;
     if (envType == "addon_parent") {
+      // Privileged addon contexts can only be loaded in documents whose main
+      // frame is also the same addon.
+      if (principal.URI.prePath !== extension.baseURI.prePath ||
+          !target.contentPrincipal.subsumes(principal)) {
+        throw new Error(`Refused to create privileged WebExtension context for ${principal.URI.spec}`);
+      }
       context = new ExtensionPageContextParent(envType, extension, data, target);
     } else if (envType == "content_parent") {
       context = new ContentScriptContextParent(envType, extension, data, target, principal);
     } else {
       throw new Error(`Invalid WebExtension context envType: ${envType}`);
     }
     this.proxyContexts.set(childId, context);
   },
@@ -532,17 +526,19 @@ ParentAPIManager = {
     let context = this.getContextById(data.childId);
     let listener = context.listenerProxies.get(data.path);
     findPathInObject(context.apiObj, data.path).removeListener(listener);
   },
 
   getContextById(childId) {
     let context = this.proxyContexts.get(childId);
     if (!context) {
-      throw new Error("WebExtension context not found!");
+      let error = new Error("WebExtension context not found!");
+      Cu.reportError(error);
+      throw error;
     }
     return context;
   },
 };
 
 ParentAPIManager.init();
 
 
--- a/toolkit/components/extensions/ExtensionTestCommon.jsm
+++ b/toolkit/components/extensions/ExtensionTestCommon.jsm
@@ -127,21 +127,18 @@ class MockExtension {
   }
 
   shutdown() {
     this.addon.uninstall();
     return this.cleanupGeneratedFile();
   }
 
   cleanupGeneratedFile() {
-    return this._extensionPromise.then(extension => {
-      return extension.broadcast("Extension:FlushJarCache", {path: this.file.path});
-    }).then(() => {
-      return OS.File.remove(this.file.path);
-    });
+    flushJarCache(this.file);
+    return OS.File.remove(this.file.path);
   }
 }
 
 class ExtensionTestCommon {
   /**
    * This code is designed to make it easy to test a WebExtension
    * without creating a bunch of files. Everything is contained in a
    * single JSON blob.
--- a/toolkit/components/extensions/ext-backgroundPage.js
+++ b/toolkit/components/extensions/ext-backgroundPage.js
@@ -6,220 +6,131 @@ Cu.import("resource://gre/modules/Servic
 Cu.import("resource://gre/modules/Task.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
 
 Cu.import("resource://gre/modules/ExtensionUtils.jsm");
 const {
   promiseDocumentLoaded,
-  promiseEvent,
   promiseObserved,
 } = ExtensionUtils;
 
 const XUL_URL = "data:application/vnd.mozilla.xul+xml;charset=utf-8," + encodeURI(
   `<?xml version="1.0"?>
   <window id="documentElement"/>`);
 
 // WeakMap[Extension -> BackgroundPage]
 var backgroundPagesMap = new WeakMap();
 
 // Responsible for the background_page section of the manifest.
-class BackgroundPageBase {
-  constructor(options, extension) {
-    this.extension = extension;
-    this.page = options.page || null;
-    this.isGenerated = !!options.scripts;
-    this.webNav = null;
-  }
+function BackgroundPage(options, extension) {
+  this.extension = extension;
+  this.page = options.page || null;
+  this.isGenerated = !!options.scripts;
+  this.windowlessBrowser = null;
+  this.webNav = null;
+}
 
-  build() {
-    return Task.spawn(function* () {
-      let url;
-      if (this.page) {
-        url = this.extension.baseURI.resolve(this.page);
-      } else if (this.isGenerated) {
-        url = this.extension.baseURI.resolve("_generated_background_page.html");
-      }
+BackgroundPage.prototype = {
+  build: Task.async(function* () {
+    let windowlessBrowser = Services.appShell.createWindowlessBrowser(true);
+    this.windowlessBrowser = windowlessBrowser;
 
-      if (!this.extension.isExtensionURL(url)) {
-        this.extension.manifestError("Background page must be a file within the extension");
-        url = this.extension.baseURI.resolve("_blank.html");
-      }
-
-      let chromeDoc = yield this.getParentDocument();
+    let url;
+    if (this.page) {
+      url = this.extension.baseURI.resolve(this.page);
+    } else if (this.isGenerated) {
+      url = this.extension.baseURI.resolve("_generated_background_page.html");
+    }
 
-      let browser = chromeDoc.createElement("browser");
-      browser.setAttribute("type", "content");
-      browser.setAttribute("disableglobalhistory", "true");
-      browser.setAttribute("webextension-view-type", "background");
+    if (!this.extension.isExtensionURL(url)) {
+      this.extension.manifestError("Background page must be a file within the extension");
+      url = this.extension.baseURI.resolve("_blank.html");
+    }
 
-      let awaitFrameLoader;
-      if (this.extension.remote) {
-        browser.setAttribute("remote", "true");
-        awaitFrameLoader = promiseEvent(browser, "XULFrameLoaderCreated");
-      }
-
-      chromeDoc.documentElement.appendChild(browser);
-      yield awaitFrameLoader;
+    let system = Services.scriptSecurityManager.getSystemPrincipal();
 
-      this.browser = browser;
-
-      extensions.emit("extension-browser-inserted", browser);
-
-      browser.loadURI(url);
+    // The windowless browser is a thin wrapper around a docShell that keeps
+    // its related resources alive. It implements nsIWebNavigation and
+    // forwards its methods to the underlying docShell, but cannot act as a
+    // docShell itself. Calling `getInterface(nsIDocShell)` gives us the
+    // underlying docShell, and `QueryInterface(nsIWebNavigation)` gives us
+    // access to the webNav methods that are already available on the
+    // windowless browser, but contrary to appearances, they are not the same
+    // object.
+    let chromeShell = windowlessBrowser.QueryInterface(Ci.nsIInterfaceRequestor)
+                                       .getInterface(Ci.nsIDocShell)
+                                       .QueryInterface(Ci.nsIWebNavigation);
 
-      yield new Promise(resolve => {
-        browser.messageManager.addMessageListener("Extension:ExtensionViewLoaded", function onLoad() {
-          browser.messageManager.removeMessageListener("Extension:ExtensionViewLoaded", onLoad);
-          resolve();
-        });
-      });
-
-      if (browser.docShell) {
-        this.webNav = browser.docShell.QueryInterface(Ci.nsIWebNavigation);
-        let window = this.webNav.document.defaultView;
+    chromeShell.useGlobalHistory = false;
+    chromeShell.createAboutBlankContentViewer(system);
+    chromeShell.loadURI(XUL_URL, 0, null, null, null);
 
 
-        // Set the add-on's main debugger global, for use in the debugger
-        // console.
-        if (this.extension.addonData.instanceID) {
-          AddonManager.getAddonByInstanceID(this.extension.addonData.instanceID)
-                      .then(addon => addon.setDebugGlobal(window));
-        }
-      }
+    yield promiseObserved("chrome-document-global-created",
+                          win => win.document == chromeShell.document);
+
+    let chromeDoc = yield promiseDocumentLoaded(chromeShell.document);
+
+    let browser = chromeDoc.createElement("browser");
+    browser.setAttribute("type", "content");
+    browser.setAttribute("disableglobalhistory", "true");
+    chromeDoc.documentElement.appendChild(browser);
+
+    extensions.emit("extension-browser-inserted", browser);
+    browser.messageManager.sendAsyncMessage("Extension:InitExtensionView", {
+      viewType: "background",
+      url,
+    });
 
-      this.extension.emit("startup");
-    }.bind(this));
-  }
+    yield new Promise(resolve => {
+      browser.messageManager.addMessageListener("Extension:ExtensionViewLoaded", function onLoad() {
+        browser.messageManager.removeMessageListener("Extension:ExtensionViewLoaded", onLoad);
+        resolve();
+      });
+    });
+
+    // TODO(robwu): This is not webext-oop compatible.
+    this.webNav = browser.docShell.QueryInterface(Ci.nsIWebNavigation);
+    let window = this.webNav.document.defaultView;
 
-  initParentWindow(chromeShell) {
-    let system = Services.scriptSecurityManager.getSystemPrincipal();
-    chromeShell.createAboutBlankContentViewer(system);
-    chromeShell.useGlobalHistory = false;
-    chromeShell.loadURI(XUL_URL, 0, null, null, null);
 
-    return promiseObserved("chrome-document-global-created",
-                           win => win.document == chromeShell.document);
-  }
+    // Set the add-on's main debugger global, for use in the debugger
+    // console.
+    if (this.extension.addonData.instanceID) {
+      AddonManager.getAddonByInstanceID(this.extension.addonData.instanceID)
+                  .then(addon => addon.setDebugGlobal(window));
+    }
+
+    this.extension.emit("startup");
+  }),
 
   shutdown() {
     if (this.extension.addonData.instanceID) {
       AddonManager.getAddonByInstanceID(this.extension.addonData.instanceID)
                   .then(addon => addon.setDebugGlobal(null));
     }
 
-    if (this.browser) {
-      this.browser.remove();
-      this.browser = null;
-    }
-
     // Navigate away from the background page to invalidate any
     // setTimeouts or other callbacks.
     if (this.webNav) {
       this.webNav.loadURI("about:blank", 0, null, null, null);
       this.webNav = null;
     }
-  }
-}
-
-/**
- * A background page loaded into a windowless browser, with no on-screen
- * representation or graphical display abilities.
- *
- * This currently does not support remote browsers, and therefore cannot
- * be used with out-of-process extensions.
- */
-class WindowlessBackgroundPage extends BackgroundPageBase {
-  constructor(options, extension) {
-    super(options, extension);
-    this.windowlessBrowser = null;
-  }
-
-  getParentDocument() {
-    return Task.spawn(function* () {
-      let windowlessBrowser = Services.appShell.createWindowlessBrowser(true);
-      this.windowlessBrowser = windowlessBrowser;
-
-      // The windowless browser is a thin wrapper around a docShell that keeps
-      // its related resources alive. It implements nsIWebNavigation and
-      // forwards its methods to the underlying docShell, but cannot act as a
-      // docShell itself. Calling `getInterface(nsIDocShell)` gives us the
-      // underlying docShell, and `QueryInterface(nsIWebNavigation)` gives us
-      // access to the webNav methods that are already available on the
-      // windowless browser, but contrary to appearances, they are not the same
-      // object.
-      let chromeShell = windowlessBrowser.QueryInterface(Ci.nsIInterfaceRequestor)
-                                         .getInterface(Ci.nsIDocShell)
-                                         .QueryInterface(Ci.nsIWebNavigation);
-
-      yield this.initParentWindow(chromeShell);
-
-      return promiseDocumentLoaded(windowlessBrowser.document);
-    }.bind(this));
-  }
-
-  shutdown() {
-    super.shutdown();
 
     this.windowlessBrowser.loadURI("about:blank", 0, null, null, null);
     this.windowlessBrowser.close();
     this.windowlessBrowser = null;
-  }
-}
-
-/**
- * A background page loaded into a visible dialog window. Only to be
- * used for debugging, and in temporary, test-only use for
- * out-of-process extensions.
- */
-class WindowedBackgroundPage extends BackgroundPageBase {
-  constructor(options, extension) {
-    super(options, extension);
-    this.parentWindow = null;
-  }
-
-  getParentDocument() {
-    return Task.spawn(function* () {
-      let window = Services.ww.openWindow(null, "about:blank", "_blank",
-                                          "chrome,alwaysLowered,dialog", null);
-
-      this.parentWindow = window;
-
-      let chromeShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                              .getInterface(Ci.nsIDocShell)
-                              .QueryInterface(Ci.nsIWebNavigation);
-
-      yield this.initParentWindow(chromeShell);
-
-      window.minimize();
-
-      return promiseDocumentLoaded(window.document);
-    }.bind(this));
-  }
-
-  shutdown() {
-    super.shutdown();
-
-    if (this.parentWindow) {
-      this.parentWindow.close();
-      this.parentWindow = null;
-    }
-  }
-}
+  },
+};
 
 /* eslint-disable mozilla/balanced-listeners */
 extensions.on("manifest_background", (type, directive, extension, manifest) => {
-  let bgPage;
-  if (extension.remote) {
-    bgPage = new WindowedBackgroundPage(manifest.background, extension);
-  } else {
-    bgPage = new WindowlessBackgroundPage(manifest.background, extension);
-  }
-
+  let bgPage = new BackgroundPage(manifest.background, extension);
   backgroundPagesMap.set(extension, bgPage);
   return bgPage.build();
 });
 
 extensions.on("shutdown", (type, extension) => {
   if (backgroundPagesMap.has(extension)) {
     backgroundPagesMap.get(extension).shutdown();
     backgroundPagesMap.delete(extension);
--- a/toolkit/components/extensions/ext-browser-content.js
+++ b/toolkit/components/extensions/ext-browser-content.js
@@ -93,17 +93,17 @@ const BrowserListener = {
         if (event.target === content.document) {
           sendAsyncMessage("Extension:BrowserContentLoaded", {url: content.location.href});
           this.handleDOMChange(true);
         }
         break;
 
       case "load":
         if (event.target.contentWindow === content) {
-          // For about:addons inline <browser>s, we currently receive a load
+          // For about:addons inline <browsers>, we currently receive a load
           // event on the <browser> element, but no load or DOMContentLoaded
           // events from the content window.
           sendAsyncMessage("Extension:BrowserContentLoaded", {url: content.location.href});
         } else if (event.target !== content.document) {
           break;
         }
 
         // We use a capturing listener, so we get this event earlier than any
--- a/toolkit/components/extensions/moz.build
+++ b/toolkit/components/extensions/moz.build
@@ -29,17 +29,14 @@ TESTING_JS_MODULES += [
     'ExtensionTestCommon.jsm',
     'ExtensionXPCShellUtils.jsm',
 ]
 
 DIRS += ['schemas']
 
 JAR_MANIFESTS += ['jar.mn']
 
-MOCHITEST_MANIFESTS += [
-    'test/mochitest/mochitest-remote.ini',
-    'test/mochitest/mochitest.ini'
-]
+MOCHITEST_MANIFESTS += ['test/mochitest/mochitest.ini']
 MOCHITEST_CHROME_MANIFESTS += ['test/mochitest/chrome.ini']
 XPCSHELL_TESTS_MANIFESTS += [
     'test/xpcshell/native_messaging.ini',
     'test/xpcshell/xpcshell.ini',
 ]
--- a/toolkit/components/extensions/test/mochitest/head.js
+++ b/toolkit/components/extensions/test/mochitest/head.js
@@ -1,23 +1,10 @@
 "use strict";
 
-// We run tests under two different configurations, from mochitest.ini and
-// mochitest-remote.ini. When running from mochitest-remote.ini, the tests are
-// copied to the sub-directory "test-oop-extensions", which we detect here, and
-// use to select our configuration.
-if (location.pathname.includes("test-oop-extensions")) {
-  add_task(() => {
-    return SpecialPowers.pushPrefEnv({set: [
-      ["dom.ipc.processCount", 1],
-      ["extensions.webextensions.remote", true],
-    ]});
-  });
-}
-
 /* exported waitForLoad */
 
 function waitForLoad(win) {
   return new Promise(resolve => {
     win.addEventListener("load", function listener() {
       win.removeEventListener("load", listener, true);
       resolve();
     }, true);
deleted file mode 100644
--- a/toolkit/components/extensions/test/mochitest/mochitest-common.ini
+++ /dev/null
@@ -1,111 +0,0 @@
-[DEFAULT]
-support-files =
-  head.js
-  file_mixed.html
-  head_webrequest.js
-  file_csp.html
-  file_csp.html^headers^
-  file_WebRequest_page3.html
-  file_webNavigation_clientRedirect.html
-  file_webNavigation_clientRedirect_httpHeaders.html
-  file_webNavigation_clientRedirect_httpHeaders.html^headers^
-  file_webNavigation_frameClientRedirect.html
-  file_webNavigation_frameRedirect.html
-  file_webNavigation_manualSubframe.html
-  file_webNavigation_manualSubframe_page1.html
-  file_webNavigation_manualSubframe_page2.html
-  file_WebNavigation_page1.html
-  file_WebNavigation_page2.html
-  file_WebNavigation_page3.html
-  file_with_about_blank.html
-  file_image_good.png
-  file_image_bad.png
-  file_image_redirect.png
-  file_style_good.css
-  file_style_bad.css
-  file_style_redirect.css
-  file_script_good.js
-  file_script_bad.js
-  file_script_redirect.js
-  file_script_xhr.js
-  file_sample.html
-  redirection.sjs
-  file_privilege_escalation.html
-  file_ext_test_api_injection.js
-  file_permission_xhr.html
-  file_teardown_test.js
-  return_headers.sjs
-  webrequest_worker.js
-
-[test_clipboard.html]
-# skip-if = # disabled test case with_permission_allow_copy, see inline comment.
-[test_ext_inIncognitoContext_window.html]
-skip-if = os == 'android' # Android does not currently support windows.
-[test_ext_geturl.html]
-[test_ext_background_canvas.html]
-[test_ext_content_security_policy.html]
-[test_ext_contentscript.html]
-[test_ext_contentscript_api_injection.html]
-[test_ext_contentscript_context.html]
-[test_ext_contentscript_create_iframe.html]
-[test_ext_contentscript_devtools_metadata.html]
-[test_ext_contentscript_exporthelpers.html]
-[test_ext_contentscript_css.html]
-[test_ext_contentscript_about_blank.html]
-[test_ext_contentscript_teardown.html]
-skip-if = (os == 'android') # Android does not support tabs API. Bug 1260250
-[test_ext_exclude_include_globs.html]
-[test_ext_i18n_css.html]
-[test_ext_generate.html]
-[test_ext_notifications.html]
-[test_ext_permission_xhr.html]
-[test_ext_runtime_connect.html]
-skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
-[test_ext_runtime_connect_twoway.html]
-skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
-[test_ext_runtime_connect2.html]
-skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
-[test_ext_runtime_disconnect.html]
-[test_ext_runtime_id.html]
-[test_ext_sandbox_var.html]
-[test_ext_sendmessage_reply.html]
-skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
-[test_ext_sendmessage_reply2.html]
-skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
-[test_ext_sendmessage_doublereply.html]
-skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
-[test_ext_sendmessage_no_receiver.html]
-[test_ext_storage_content.html]
-[test_ext_storage_tab.html]
-skip-if = os == 'android' # Android does not currently support tabs.
-[test_ext_test.html]
-[test_ext_cookies.html]
-skip-if = os == 'android' # Bug 1258975 on android.
-[test_ext_background_api_injection.html]
-[test_ext_background_generated_url.html]
-[test_ext_background_teardown.html]
-[test_ext_tab_teardown.html]
-skip-if = (os == 'android') # Android does not support tabs API. Bug 1260250
-[test_ext_unload_frame.html]
-[test_ext_i18n.html]
-skip-if = (os == 'android') # Bug 1258975 on android.
-[test_ext_web_accessible_resources.html]
-skip-if = (os == 'android') # Bug 1258975 on android.
-[test_ext_webrequest_background_events.html]
-skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
-[test_ext_webrequest_basic.html]
-skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
-[test_ext_webrequest_filter.html]
-skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
-[test_ext_webrequest_suspend.html]
-skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
-[test_ext_webrequest_upload.html]
-skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
-[test_ext_webnavigation.html]
-skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
-[test_ext_webnavigation_filters.html]
-skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
-[test_ext_window_postMessage.html]
-[test_ext_subframes_privileges.html]
-skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
-[test_ext_xhr_capabilities.html]
deleted file mode 100644
--- a/toolkit/components/extensions/test/mochitest/mochitest-remote.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-[DEFAULT]
-# This is a horrible hack:
-# In order to run tests under two configurations, we create two mochitest
-# manifests, and include a manifest with a common set of tests from each. In
-# order to detect which manifest we're running from, we install the tests listed
-# in this manifest to the sub-directory "test-oop-extensions", and then check
-# whether we're running from that directory from head.js
-install-to-subdir = test-oop-extensions
-tags = webextensions remote-webextensions
-skip-if = !e10s || os == 'android'
-
-[include:mochitest-common.ini]
--- a/toolkit/components/extensions/test/mochitest/mochitest.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest.ini
@@ -1,5 +1,112 @@
 [DEFAULT]
-tags = webextensions in-process-webextensions
+support-files =
+  head.js
+  file_mixed.html
+  head_webrequest.js
+  file_csp.html
+  file_csp.html^headers^
+  file_WebRequest_page3.html
+  file_webNavigation_clientRedirect.html
+  file_webNavigation_clientRedirect_httpHeaders.html
+  file_webNavigation_clientRedirect_httpHeaders.html^headers^
+  file_webNavigation_frameClientRedirect.html
+  file_webNavigation_frameRedirect.html
+  file_webNavigation_manualSubframe.html
+  file_webNavigation_manualSubframe_page1.html
+  file_webNavigation_manualSubframe_page2.html
+  file_WebNavigation_page1.html
+  file_WebNavigation_page2.html
+  file_WebNavigation_page3.html
+  file_with_about_blank.html
+  file_image_good.png
+  file_image_bad.png
+  file_image_redirect.png
+  file_style_good.css
+  file_style_bad.css
+  file_style_redirect.css
+  file_script_good.js
+  file_script_bad.js
+  file_script_redirect.js
+  file_script_xhr.js
+  file_sample.html
+  redirection.sjs
+  file_privilege_escalation.html
+  file_ext_test_api_injection.js
+  file_permission_xhr.html
+  file_teardown_test.js
+  return_headers.sjs
+  webrequest_worker.js
+tags = webextensions
 
-
-[include:mochitest-common.ini]
+[test_clipboard.html]
+# skip-if = # disabled test case with_permission_allow_copy, see inline comment.
+[test_ext_inIncognitoContext_window.html]
+skip-if = os == 'android' # Android does not currently support windows.
+[test_ext_geturl.html]
+[test_ext_background_canvas.html]
+[test_ext_content_security_policy.html]
+[test_ext_contentscript.html]
+[test_ext_contentscript_api_injection.html]
+[test_ext_contentscript_context.html]
+[test_ext_contentscript_create_iframe.html]
+[test_ext_contentscript_devtools_metadata.html]
+[test_ext_contentscript_exporthelpers.html]
+[test_ext_contentscript_css.html]
+[test_ext_contentscript_about_blank.html]
+[test_ext_contentscript_teardown.html]
+skip-if = (os == 'android') # Android does not support tabs API. Bug 1260250
+[test_ext_exclude_include_globs.html]
+[test_ext_i18n_css.html]
+[test_ext_generate.html]
+[test_ext_notifications.html]
+[test_ext_permission_xhr.html]
+[test_ext_runtime_connect.html]
+skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
+[test_ext_runtime_connect_twoway.html]
+skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
+[test_ext_runtime_connect2.html]
+skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
+[test_ext_runtime_disconnect.html]
+[test_ext_runtime_id.html]
+[test_ext_sandbox_var.html]
+[test_ext_sendmessage_reply.html]
+skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
+[test_ext_sendmessage_reply2.html]
+skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
+[test_ext_sendmessage_doublereply.html]
+skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
+[test_ext_sendmessage_no_receiver.html]
+[test_ext_storage_content.html]
+[test_ext_storage_tab.html]
+skip-if = os == 'android' # Android does not currently support tabs.
+[test_ext_test.html]
+[test_ext_cookies.html]
+skip-if = os == 'android' # Bug 1258975 on android.
+[test_ext_background_api_injection.html]
+[test_ext_background_generated_url.html]
+[test_ext_background_teardown.html]
+[test_ext_tab_teardown.html]
+skip-if = (os == 'android') # Android does not support tabs API. Bug 1260250
+[test_ext_unload_frame.html]
+[test_ext_i18n.html]
+skip-if = (os == 'android') # Bug 1258975 on android.
+[test_ext_web_accessible_resources.html]
+skip-if = (os == 'android') # Bug 1258975 on android.
+[test_ext_webrequest_background_events.html]
+skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
+[test_ext_webrequest_basic.html]
+skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
+[test_ext_webrequest_filter.html]
+skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
+[test_ext_webrequest_suspend.html]
+skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
+[test_ext_webrequest_upload.html]
+skip-if = os == 'android' # webrequest api unsupported (bug 1258975).
+[test_ext_webnavigation.html]
+skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
+[test_ext_webnavigation_filters.html]
+skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
+[test_ext_window_postMessage.html]
+[test_ext_subframes_privileges.html]
+skip-if = os == 'android' # port.sender.tab is undefined on Android (bug 1258975).
+[test_ext_xhr_capabilities.html]
--- a/toolkit/components/extensions/test/mochitest/test_ext_webrequest_background_events.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest_background_events.html
@@ -90,17 +90,17 @@ add_task(function* test_webRequest_backg
       for (let name of eventNames) {
         browser.webRequest[name].addListener(
           listener.bind(null, name),
           {urls: ["https://example.com/*"]}
         );
       }
 
       fetch("https://example.com/example.txt").then(() => {
-        browser.test.succeed("Fetch succeeded.");
+        browser.test.pass("Fetch succeeded.");
       }, () => {
         browser.test.fail("fetch recieved");
         browser.test.sendMessage("done");
       });
     },
   });
 
   yield extension.startup();
--- a/toolkit/components/extensions/test/mochitest/test_ext_webrequest_basic.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest_basic.html
@@ -1,18 +1,18 @@
 <!DOCTYPE HTML>
 
 <html>
 <head>
 <meta charset="utf-8">
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
+  <script type="text/javascript" src="head.js"></script>
   <script type="text/javascript" src="head_webrequest.js"></script>
-  <script type="text/javascript" src="head.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 <script>
 "use strict";
 
 let extension;
 add_task(function* setup() {
   // Clear the image cache, since it gets in the way otherwise.
   let imgTools = SpecialPowers.Cc["@mozilla.org/image/tools;1"].getService(SpecialPowers.Ci.imgITools);
--- a/toolkit/components/viewsource/content/viewSource.css
+++ b/toolkit/components/viewsource/content/viewSource.css
@@ -1,7 +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/. */
 
 toolbar[printpreview="true"] {
   -moz-binding: url("chrome://global/content/printPreviewBindings.xml#printpreviewtoolbar");
 }
+
+browser[remote="true"] {
+  -moz-binding: url("chrome://global/content/bindings/remote-browser.xml#remote-browser");
+}
\ No newline at end of file
--- a/toolkit/content/xul.css
+++ b/toolkit/content/xul.css
@@ -163,20 +163,16 @@ editor,
 iframe {
   display: inline;
 }
 
 browser {
   -moz-binding: url("chrome://global/content/bindings/browser.xml#browser");
 }
 
-browser[remote=true] {
-  -moz-binding: url("chrome://global/content/bindings/remote-browser.xml#remote-browser");
-}
-
 editor {
   -moz-binding: url("chrome://global/content/bindings/editor.xml#editor");
 }
 
 iframe {
   -moz-binding: url("chrome://global/content/bindings/general.xml#iframe");
 }
 
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -8,26 +8,21 @@
 /* globals XMLStylesheetProcessingInstruction*/
 
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 var Cu = Components.utils;
 var Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/DownloadUtils.jsm");
 Cu.import("resource://gre/modules/AddonManager.jsm");
 Cu.import("resource://gre/modules/addons/AddonRepository.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils", "resource:///modules/E10SUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "ExtensionParent",
-                                  "resource://gre/modules/ExtensionParent.jsm");
-
 const CONSTANTS = {};
 Cu.import("resource://gre/modules/addons/AddonConstants.jsm", CONSTANTS);
 const SIGNING_REQUIRED = CONSTANTS.REQUIRE_SIGNING ?
                          true :
                          Services.prefs.getBoolPref("xpinstall.signatures.required");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
                                   "resource://gre/modules/PluralForm.jsm");
@@ -129,51 +124,43 @@ class MessageDispatcher {
  * @param {Element} browser
  *        A XUL <browser> element.
  */
 class FakeFrameMessageManager {
   constructor(browser) {
     let dispatcher = new MessageDispatcher(browser);
     let frameDispatcher = new MessageDispatcher(null);
 
-    let bind = (object, method) => object[method].bind(object);
-
-    this.sendAsyncMessage = bind(frameDispatcher, "sendAsyncMessage");
-    this.addMessageListener = bind(dispatcher, "addMessageListener");
-    this.removeMessageListener = bind(dispatcher, "removeMessageListener");
+    this.sendAsyncMessage = frameDispatcher.sendAsyncMessage.bind(frameDispatcher);
+    this.addMessageListener = dispatcher.addMessageListener.bind(dispatcher);
+    this.removeMessageListener = dispatcher.removeMessageListener.bind(dispatcher);
 
     this.frame = {
       get content() {
         return browser.contentWindow;
       },
 
       get docShell() {
         return browser.docShell;
       },
 
-      addEventListener: bind(browser, "addEventListener"),
-      removeEventListener: bind(browser, "removeEventListener"),
-
-      sendAsyncMessage: bind(dispatcher, "sendAsyncMessage"),
-      addMessageListener: bind(frameDispatcher, "addMessageListener"),
-      removeMessageListener: bind(frameDispatcher, "removeMessageListener"),
+      addEventListener: browser.addEventListener.bind(browser),
+      removeEventListener: browser.removeEventListener.bind(browser),
+
+      sendAsyncMessage: dispatcher.sendAsyncMessage.bind(dispatcher),
+      addMessageListener: frameDispatcher.addMessageListener.bind(frameDispatcher),
+      removeMessageListener: frameDispatcher.removeMessageListener.bind(frameDispatcher),
     }
   }
 
   loadFrameScript(url) {
     Services.scriptloader.loadSubScript(url, Object.create(this.frame));
   }
 }
 
-function promiseEvent(event, target, capture = false) {
-  return new Promise(resolve => {
-    target.addEventListener(event, resolve, {capture, once: true});
-  });
-}
-
 var gPendingInitializations = 1;
 Object.defineProperty(this, "gIsInitializing", {
   get: () => gPendingInitializations > 0
 });
 
 function initialize(event) {
   // XXXbz this listener gets _all_ load events for all nodes in the
   // document... but relies on not being called "too early".
@@ -3525,63 +3512,50 @@ var gDetailView = {
 
       let detailViewBoxObject = gDetailView.node.boxObject;
       top -= detailViewBoxObject.y;
 
       detailViewBoxObject.scrollTo(0, top);
     }
   },
 
-  createOptionsBrowser: Task.async(function*(parentNode) {
+  createOptionsBrowser: function(parentNode) {
     let browser = document.createElement("browser");
     browser.setAttribute("type", "content");
     browser.setAttribute("disableglobalhistory", "true");
     browser.setAttribute("class", "inline-options-browser");
 
-    let {optionsURL} = this._addon;
-    let remote = !E10SUtils.canLoadURIInProcess(optionsURL, Services.appinfo.PROCESS_TYPE_DEFAULT);
-
-    let readyPromise;
-    if (remote) {
-      browser.setAttribute("remote", "true");
-      readyPromise = promiseEvent("XULFrameLoaderCreated", browser);
-    } else {
-      readyPromise = promiseEvent("load", browser, true);
-    }
-
-    parentNode.appendChild(browser);
-
-    // Force bindings to apply synchronously.
-    browser.clientTop;
-
-    yield readyPromise;
-    if (remote) {
-      ExtensionParent.apiManager.emit("extension-browser-inserted", browser);
-    }
-
-    return new Promise(resolve => {
+    return new Promise((resolve, reject) => {
       let messageListener = {
         receiveMessage({name, data}) {
           if (name === "Extension:BrowserResized")
             browser.style.height = `${data.height}px`;
           else if (name === "Extension:BrowserContentLoaded")
             resolve(browser);
         },
       };
 
-      let mm = browser.messageManager || new FakeFrameMessageManager(browser);
-      mm.loadFrameScript("chrome://extensions/content/ext-browser-content.js",
-                         false);
-      mm.addMessageListener("Extension:BrowserContentLoaded", messageListener);
-      mm.addMessageListener("Extension:BrowserResized", messageListener);
-      mm.sendAsyncMessage("Extension:InitBrowser", {fixedWidth: true});
-
-      browser.loadURI(optionsURL);
+      let onload = () => {
+        browser.removeEventListener("load", onload, true);
+
+        let mm = new FakeFrameMessageManager(browser);
+        mm.loadFrameScript("chrome://extensions/content/ext-browser-content.js",
+                           false);
+        mm.addMessageListener("Extension:BrowserContentLoaded", messageListener);
+        mm.addMessageListener("Extension:BrowserResized", messageListener);
+        mm.sendAsyncMessage("Extension:InitBrowser", {fixedWidth: true});
+
+        browser.setAttribute("src", this._addon.optionsURL);
+      };
+      browser.addEventListener("load", onload, true);
+      browser.addEventListener("error", reject);
+
+      parentNode.appendChild(browser);
     });
-  }),
+  },
 
   getSelectedAddon: function() {
     return this._addon;
   },
 
   onEnabling: function() {
     this.updateState();
   },
--- a/toolkit/mozapps/extensions/test/browser/browser_inlinesettings_browser.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_inlinesettings_browser.js
@@ -119,24 +119,22 @@ add_task(function* test_inline_browser_a
 
   function checkHeights(expected) {
     is(body.clientHeight, expected, `Document body should be ${expected}px tall`);
     is(body.clientHeight, body.scrollHeight,
        "Document body should be tall enough to fit its contents");
 
     let heightDiff = browser.clientHeight - expected;
     ok(heightDiff >= 0 && heightDiff < 50,
-       `Browser should be slightly taller than the document body (${browser.clientHeight} vs. ${expected})`);
+       "Browser should be slightly taller than the document body");
   }
 
   // Delay long enough to avoid hitting our resize rate limit.
   let delay = () => new Promise(resolve => setTimeout(resolve, 300));
 
-  yield delay();
-
   checkHeights(300);
 
   info("Increase the document height, and expect the browser to grow correspondingly");
   body.classList.toggle("bigger");
 
   yield delay();
 
   checkHeights(600);