Bug 952201 - Make installing addons from web content work correctly in e10s. r=bmcbride@mozilla.com
authorBlake Kaplan <mrbkap@gmail.com>
Fri, 18 Jul 2014 09:27:29 -0700
changeset 194945 53f37bbfd7ab187f41f728a9f8f52e293e33bd8b
parent 194944 d323591130d0dfe8c3d7590d0d65e7bb3361c075
child 194946 39460d5525e5bb6e30fe9874057f7ba64fa97fbd
push id27160
push userkwierso@gmail.com
push dateSat, 19 Jul 2014 00:51:52 +0000
treeherdermozilla-central@9fdb8047f07d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbmcbride
bugs952201
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 952201 - Make installing addons from web content work correctly in e10s. r=bmcbride@mozilla.com
browser/base/content/browser-addons.js
toolkit/mozapps/extensions/AddonManager.jsm
toolkit/mozapps/extensions/addonManager.js
toolkit/mozapps/extensions/amIWebInstallListener.idl
toolkit/mozapps/extensions/amIWebInstaller.idl
toolkit/mozapps/extensions/amInstallTrigger.js
toolkit/mozapps/extensions/amWebInstallListener.js
toolkit/mozapps/extensions/nsBlocklistService.js
toolkit/mozapps/extensions/test/browser/browser_bug567127.js
toolkit/mozapps/extensions/test/browser/browser_dragdrop.js
toolkit/mozapps/extensions/test/mochitest/mochitest.ini
toolkit/mozapps/extensions/test/xpinstall/browser_bug645699.js
toolkit/mozapps/extensions/test/xpinstall/browser_whitelist.js
toolkit/mozapps/extensions/test/xpinstall/browser_whitelist2.js
toolkit/mozapps/extensions/test/xpinstall/browser_whitelist4.js
toolkit/mozapps/extensions/test/xpinstall/browser_whitelist5.js
toolkit/mozapps/extensions/test/xpinstall/browser_whitelist6.js
--- a/browser/base/content/browser-addons.js
+++ b/browser/base/content/browser-addons.js
@@ -27,21 +27,28 @@ const gXPInstallObserver = {
     }
     return null;
   },
 
   observe: function (aSubject, aTopic, aData)
   {
     var brandBundle = document.getElementById("bundle_brand");
     var installInfo = aSubject.QueryInterface(Components.interfaces.amIWebInstallInfo);
-    var win = installInfo.originatingWindow;
-    var shell = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                   .getInterface(Components.interfaces.nsIWebNavigation)
-                   .QueryInterface(Components.interfaces.nsIDocShell);
-    var browser = this._getBrowser(shell);
+    var winOrBrowser = installInfo.originator;
+
+    var browser;
+    try {
+      var shell = winOrBrowser.QueryInterface(Components.interfaces.nsIDOMWindow)
+                              .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                              .getInterface(Components.interfaces.nsIWebNavigation)
+                              .QueryInterface(Components.interfaces.nsIDocShell);
+      browser = this._getBrowser(shell);
+    } catch (e) {
+      browser = winOrBrowser;
+    }
     if (!browser)
       return;
     const anchorID = "addons-notification-icon";
     var messageString, action;
     var brandShortName = brandBundle.getString("brandShortName");
 
     var notificationID = aTopic;
     // Make notifications persist a minimum of 30 seconds
--- a/toolkit/mozapps/extensions/AddonManager.jsm
+++ b/toolkit/mozapps/extensions/AddonManager.jsm
@@ -1816,18 +1816,18 @@ var AddonManagerInternal = {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (!aMimetype || typeof aMimetype != "string")
       throw Components.Exception("aMimetype must be a non-empty string",
                                  Cr.NS_ERROR_INVALID_ARG);
 
-    if (aSource && !(aSource instanceof Ci.nsIDOMWindow))
-      throw Components.Exception("aSource must be a nsIDOMWindow or null",
+    if (aSource && !(aSource instanceof Ci.nsIDOMWindow) && !(aSource instanceof Ci.nsIDOMNode))
+      throw Components.Exception("aSource must be a nsIDOMWindow, a XUL element, or null",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     if (aURI && !(aURI instanceof Ci.nsIURI))
       throw Components.Exception("aURI must be a nsIURI or null",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     if (!Array.isArray(aInstalls))
       throw Components.Exception("aInstalls must be an array",
--- a/toolkit/mozapps/extensions/addonManager.js
+++ b/toolkit/mozapps/extensions/addonManager.js
@@ -37,21 +37,21 @@ let gParentMM = null;
 
 
 function amManager() {
   Cu.import("resource://gre/modules/AddonManager.jsm");
 
   let globalMM = Cc["@mozilla.org/globalmessagemanager;1"]
                  .getService(Ci.nsIMessageListenerManager);
   globalMM.loadFrameScript(CHILD_SCRIPT, true);
+  globalMM.addMessageListener(MSG_INSTALL_ADDONS, this);
 
   gParentMM = Cc["@mozilla.org/parentprocessmessagemanager;1"]
                  .getService(Ci.nsIMessageListenerManager);
   gParentMM.addMessageListener(MSG_INSTALL_ENABLED, this);
-  gParentMM.addMessageListener(MSG_INSTALL_ADDONS, this);
 }
 
 amManager.prototype = {
   observe: function AMC_observe(aSubject, aTopic, aData) {
     if (aTopic == "addons-startup")
       AddonManagerPrivate.startup();
   },
 
@@ -69,43 +69,44 @@ amManager.prototype = {
   isInstallEnabled: function AMC_isInstallEnabled(aMimetype, aReferer) {
     return AddonManager.isInstallEnabled(aMimetype);
   },
 
   /**
    * @see amIWebInstaller.idl
    */
   installAddonsFromWebpage: function AMC_installAddonsFromWebpage(aMimetype,
-                                                                  aWindow,
+                                                                  aOriginator,
                                                                   aReferer, aUris,
                                                                   aHashes, aNames,
                                                                   aIcons, aCallback) {
     if (aUris.length == 0)
       return false;
 
     let retval = true;
     if (!AddonManager.isInstallAllowed(aMimetype, aReferer)) {
       aCallback = null;
       retval = false;
     }
 
     let loadGroup = null;
 
     try {
-      loadGroup = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                         .getInterface(Ci.nsIWebNavigation)
-                         .QueryInterface(Ci.nsIDocumentLoader).loadGroup;
+      loadGroup = aOriginator.QueryInterface(Ci.nsIDOMWindow)
+                             .QueryInterface(Ci.nsIInterfaceRequestor)
+                             .getInterface(Ci.nsIWebNavigation)
+                             .QueryInterface(Ci.nsIDocumentLoader).loadGroup;
     }
     catch (e) {
     }
 
     let installs = [];
     function buildNextInstall() {
       if (aUris.length == 0) {
-        AddonManager.installAddonsFromWebpage(aMimetype, aWindow, aReferer, installs);
+        AddonManager.installAddonsFromWebpage(aMimetype, aOriginator, aReferer, installs);
         return;
       }
       let uri = aUris.shift();
       AddonManager.getInstallForURL(uri, function buildNextInstall_getInstallForURL(aInstall) {
         function callCallback(aUri, aStatus) {
           try {
             aCallback.onInstallEnded(aUri, aStatus);
           }
@@ -163,37 +164,38 @@ amManager.prototype = {
   receiveMessage: function AMC_receiveMessage(aMessage) {
     let payload = aMessage.data;
     let referer = Services.io.newURI(payload.referer, null, null);
 
     switch (aMessage.name) {
       case MSG_INSTALL_ENABLED:
         return this.isInstallEnabled(payload.mimetype, referer);
 
-      case MSG_INSTALL_ADDONS:
+      case MSG_INSTALL_ADDONS: {
         let callback = null;
         if (payload.callbackID != -1) {
           callback = {
             onInstallEnded: function ITP_callback(url, status) {
               gParentMM.broadcastAsyncMessage(MSG_INSTALL_CALLBACK, {
                 callbackID: payload.callbackID,
                 url: url,
                 status: status
               });
             },
           };
         }
 
-        // Should reimplement this properly with Window IDs when possible,
-        // see bug 596109.
-        let window = aMessage.objects.win;
-
+        // If aMessage.objects.window exists, then we're same-process and we
+        // can target any modal prompts more correctly. Otherwise, we use the
+        // browser element for the remote browser as the best bet.
+        let originator = aMessage.objects.window || aMessage.target;
         return this.installAddonsFromWebpage(payload.mimetype,
-          window, referer, payload.uris, payload.hashes, payload.names,
-          payload.icons, callback);
+          originator, referer, payload.uris, payload.hashes,
+          payload.names, payload.icons, callback);
+      }
     }
   },
 
   classID: Components.ID("{4399533d-08d1-458c-a87a-235f74451cfa}"),
   _xpcom_factory: {
     createInstance: function AMC_createInstance(aOuter, aIid) {
       if (aOuter != null)
         throw Components.Exception("Component does not support aggregation",
--- a/toolkit/mozapps/extensions/amIWebInstallListener.idl
+++ b/toolkit/mozapps/extensions/amIWebInstallListener.idl
@@ -8,20 +8,20 @@ interface nsIDOMWindow;
 interface nsIURI;
 interface nsIVariant;
 
 /**
  * amIWebInstallInfo is used by the default implementation of
  * amIWebInstallListener to communicate with the running application and allow
  * it to warn the user about blocked installs and start the installs running.
  */
-[scriptable, uuid(8710e692-3989-4dc7-b607-40d57610ae75)]
+[scriptable, uuid(502f206a-c6b4-4e98-b442-e335792e2594)]
 interface amIWebInstallInfo : nsISupports
 {
-  readonly attribute nsIDOMWindow originatingWindow;
+  readonly attribute nsISupports originator;
   readonly attribute nsIURI originatingURI;
   readonly attribute nsIVariant installs;
 
   /**
    * Starts all installs.
    */
   void install();
 };
@@ -33,61 +33,61 @@ interface amIWebInstallInfo : nsISupport
  * notify when installations are blocked.
  */
 [scriptable, uuid(a5503979-89c8-441e-9e4a-321df379c172)]
 interface amIWebInstallListener : nsISupports
 {
   /**
    * Called when installation by websites is currently disabled.
    *
-   * @param  aWindow
-   *         The window that triggered the installs
+   * @param  aOriginator
+   *         The window or browser that triggered the installs
    * @param  aUri
    *         The URI of the site that triggered the installs
    * @param  aInstalls
    *         The AddonInstalls that were blocked
    * @param  aCount
    *         The number of AddonInstalls
    */
-  void onWebInstallDisabled(in nsIDOMWindow aWindow, in nsIURI aUri,
+  void onWebInstallDisabled(in nsISupports aOriginator, in nsIURI aUri,
                             [array, size_is(aCount)] in nsIVariant aInstalls,
                             [optional] in uint32_t aCount);
 
   /**
    * Called when the website is not allowed to directly prompt the user to
    * install add-ons.
    *
    * @param  aWindow
-   *         The window that triggered the installs
+   *         The window or browser that triggered the installs
    * @param  aUri
    *         The URI of the site that triggered the installs
    * @param  aInstalls
    *         The AddonInstalls that were blocked
    * @param  aCount
    *         The number of AddonInstalls
    * @return true if the caller should start the installs
    */
-  boolean onWebInstallBlocked(in nsIDOMWindow aWindow, in nsIURI aUri,
+  boolean onWebInstallBlocked(in nsISupports aOriginator, in nsIURI aUri,
                               [array, size_is(aCount)] in nsIVariant aInstalls,
                               [optional] in uint32_t aCount);
 
   /**
    * Called when a website wants to ask the user to install add-ons.
    *
    * @param  aWindow
-   *         The window that triggered the installs
+   *         The window or browser that triggered the installs
    * @param  aUri
    *         The URI of the site that triggered the installs
    * @param  aInstalls
    *         The AddonInstalls that were requested
    * @param  aCount
    *         The number of AddonInstalls
    * @return true if the caller should start the installs
    */
-  boolean onWebInstallRequested(in nsIDOMWindow aWindow, in nsIURI aUri,
+  boolean onWebInstallRequested(in nsISupports aOriginator, in nsIURI aUri,
                                 [array, size_is(aCount)] in nsIVariant aInstalls,
                                 [optional] in uint32_t aCount);
 };
 
 /**
  * amIWebInstallPrompt is used, if available, by the default implementation of 
  * amIWebInstallInfo to display a confirmation UI to the user before running
  * installs.
--- a/toolkit/mozapps/extensions/amIWebInstaller.idl
+++ b/toolkit/mozapps/extensions/amIWebInstaller.idl
@@ -27,17 +27,17 @@ interface amIInstallCallback : nsISuppor
    */
   void onInstallEnded(in AString aUrl, in int32_t aStatus);
 };
 
 
 /**
  * This interface is used to allow webpages to start installing add-ons.
  */
-[scriptable, uuid(4fdf4f84-73dc-4857-9bbe-84895e8afd5d)]
+[scriptable, uuid(8565a9c7-daf9-4af5-aae0-b272afcbccaa)]
 interface amIWebInstaller : nsISupports
 {
   /**
    * Checks if installation is enabled for a webpage.
    *
    * @param  aMimetype
    *         The mimetype for the add-on to be installed
    * @param  referer
@@ -46,18 +46,19 @@ interface amIWebInstaller : nsISupports
    */
   boolean isInstallEnabled(in AString aMimetype, in nsIURI aReferer);
 
   /**
    * Installs an array of add-ons at the request of a webpage
    *
    * @param  aMimetype
    *         The mimetype for the add-ons
-   * @param  aWindow
-   *         The window installing the add-ons
+   * @param  aOriginator
+   *         If not e10s, the window installing the add-ons, otherwise the
+   *         browser installing the add-ons.
    * @param  aReferer
    *         The URI for the webpage installing the add-ons
    * @param  aUris
    *         The URIs of add-ons to be installed
    * @param  aHashes
    *         The hashes for the add-ons to be installed
    * @param  aNames
    *         The names for the add-ons to be installed
@@ -66,17 +67,17 @@ interface amIWebInstaller : nsISupports
    * @param  aCallback
    *         An optional callback to notify about installation success and
    *         failure
    * @param  aInstallCount
    *         An optional argument including the number of add-ons to install
    * @return true if the installation was successfully started
    */
   boolean installAddonsFromWebpage(in AString aMimetype,
-                                   in nsIDOMWindow aWindow,
+                                   in nsISupports aOriginator,
                                    in nsIURI aReferer,
                                    [array, size_is(aInstallCount)] in wstring aUris,
                                    [array, size_is(aInstallCount)] in wstring aHashes,
                                    [array, size_is(aInstallCount)] in wstring aNames,
                                    [array, size_is(aInstallCount)] in wstring aIcons,
                                    [optional] in amIInstallCallback aCallback,
                                    [optional] in uint32_t aInstallCount);
 };
--- a/toolkit/mozapps/extensions/amInstallTrigger.js
+++ b/toolkit/mozapps/extensions/amInstallTrigger.js
@@ -63,23 +63,33 @@ RemoteMediator.prototype = {
     let params = {
       referer: url,
       mimetype: XPINSTALL_MIMETYPE
     };
     return this.mm.sendSyncMessage(MSG_INSTALL_ENABLED, params)[0];
   },
 
   install: function(installs, referer, callback, window) {
+    let messageManager = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                         .getInterface(Ci.nsIWebNavigation)
+                         .QueryInterface(Ci.nsIDocShell)
+                         .QueryInterface(Ci.nsIInterfaceRequestor)
+                         .getInterface(Ci.nsIContentFrameMessageManager);
+
     let callbackID = this._addCallback(callback, installs.uris);
 
     installs.mimetype = XPINSTALL_MIMETYPE;
     installs.referer = referer;
     installs.callbackID = callbackID;
 
-    return this.mm.sendSyncMessage(MSG_INSTALL_ADDONS, installs, {win: window})[0];
+    let objects = { window: null };
+    if (Services.appinfo.processType === Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT)
+      objects.window = window;
+
+    return messageManager.sendSyncMessage(MSG_INSTALL_ADDONS, installs, objects)[0];
   },
 
   _addCallback: function(callback, urls) {
     if (!callback || typeof callback != "function")
       return -1;
 
     let callbackID = this._windowID + "-" + ++this._lastCallbackID;
     let callbackObject = new CallbackObject(callbackID, callback, urls, this);
--- a/toolkit/mozapps/extensions/amWebInstallListener.js
+++ b/toolkit/mozapps/extensions/amWebInstallListener.js
@@ -32,59 +32,59 @@ const READY_STATES = [
 
 Cu.import("resource://gre/modules/Log.jsm");
 const LOGGER_ID = "addons.weblistener";
 
 // Create a new logger for use by the Addons Web Listener
 // (Requires AddonManager.jsm)
 let logger = Log.repository.getLogger(LOGGER_ID);
 
-function notifyObservers(aTopic, aWindow, aUri, aInstalls) {
+function notifyObservers(aTopic, aOriginator, aUri, aInstalls) {
   let info = {
-    originatingWindow: aWindow,
+    originator: aOriginator,
     originatingURI: aUri,
     installs: aInstalls,
 
     QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallInfo])
   };
   Services.obs.notifyObservers(info, aTopic, null);
 }
 
 /**
  * Creates a new installer to monitor downloads and prompt to install when
  * ready
  *
- * @param  aWindow
- *         The window that started the installations
+ * @param  aOriginator
+ *         The window or browser that started the installations
  * @param  aUrl
  *         The URL that started the installations
  * @param  aInstalls
  *         An array of AddonInstalls
  */
-function Installer(aWindow, aUrl, aInstalls) {
-  this.window = aWindow;
+function Installer(aOriginator, aUrl, aInstalls) {
+  this.originator = aOriginator;
   this.url = aUrl;
   this.downloads = aInstalls;
   this.installed = [];
 
-  notifyObservers("addon-install-started", aWindow, aUrl, aInstalls);
+  notifyObservers("addon-install-started", aOriginator, aUrl, aInstalls);
 
   aInstalls.forEach(function(aInstall) {
     aInstall.addListener(this);
 
     // Start downloading if it hasn't already begun
     if (READY_STATES.indexOf(aInstall.state) != -1)
       aInstall.install();
   }, this);
 
   this.checkAllDownloaded();
 }
 
 Installer.prototype = {
-  window: null,
+  originator: null,
   downloads: null,
   installed: null,
   isDownloading: true,
 
   /**
    * Checks if all downloads are now complete and if so prompts to install.
    */
   checkAllDownloaded: function Installer_checkAllDownloaded() {
@@ -140,55 +140,64 @@ Installer.prototype = {
       // Stop listening and cancel any installs that are failed because of
       // compatibility reasons.
       failed.forEach(function(aInstall) {
         if (aInstall.state == AddonManager.STATE_DOWNLOADED) {
           aInstall.removeListener(this);
           aInstall.cancel();
         }
       }, this);
-      notifyObservers("addon-install-failed", this.window, this.url, failed);
+      notifyObservers("addon-install-failed", this.originator, this.url, failed);
     }
 
     // If none of the downloads were successful then exit early
     if (this.downloads.length == 0)
       return;
 
+    let parentWindow = null;
+    try {
+      parentWindow = this.originator.QueryInterface(Ci.nsIDOMWindow);
+    } catch (e) {
+      // If we're remote, then originator will be a browser. In that case,
+      // we're showing our dialog on behalf of a content process and passing
+      // null is the best we can do for now.
+    }
+
     // Check for a custom installation prompt that may be provided by the
     // applicaton
     if ("@mozilla.org/addons/web-install-prompt;1" in Cc) {
       try {
         let prompt = Cc["@mozilla.org/addons/web-install-prompt;1"].
                      getService(Ci.amIWebInstallPrompt);
-        prompt.confirm(this.window, this.url, this.downloads, this.downloads.length);
+        prompt.confirm(parentWindow, this.url, this.downloads, this.downloads.length);
         return;
       }
       catch (e) {}
     }
 
     let args = {};
     args.url = this.url;
     args.installs = this.downloads;
     args.wrappedJSObject = args;
 
     try {
       Cc["@mozilla.org/base/telemetry;1"].
             getService(Ci.nsITelemetry).
             getHistogramById("SECURITY_UI").
             add(Ci.nsISecurityUITelemetry.WARNING_CONFIRM_ADDON_INSTALL);
-      Services.ww.openWindow(this.window, URI_XPINSTALL_DIALOG,
+      Services.ww.openWindow(parentWindow, URI_XPINSTALL_DIALOG,
                              null, "chrome,modal,centerscreen", args);
     } catch (e) {
       this.downloads.forEach(function(aInstall) {
         aInstall.removeListener(this);
         // Cancel the installs, as currently there is no way to make them fail
         // from here.
         aInstall.cancel();
       }, this);
-      notifyObservers("addon-install-cancelled", this.window, this.url,
+      notifyObservers("addon-install-cancelled", this.originator, this.url,
                       this.downloads);
     }
   },
 
   /**
    * Checks if all installs are now complete and if so notifies observers.
    */
   checkAllInstalled: function Installer_checkAllInstalled() {
@@ -205,20 +214,20 @@ Installer.prototype = {
         failed.push(install);
         break;
       }
     }
 
     this.downloads = null;
 
     if (failed.length > 0)
-      notifyObservers("addon-install-failed", this.window, this.url, failed);
+      notifyObservers("addon-install-failed", this.originator, this.url, failed);
 
     if (this.installed.length > 0)
-      notifyObservers("addon-install-complete", this.window, this.url, this.installed);
+      notifyObservers("addon-install-complete", this.originator, this.url, this.installed);
     this.installed = null;
   },
 
   onDownloadCancelled: function Installer_onDownloadCancelled(aInstall) {
     aInstall.removeListener(this);
     this.checkAllDownloaded();
   },
 
@@ -259,52 +268,52 @@ Installer.prototype = {
 
 function extWebInstallListener() {
 }
 
 extWebInstallListener.prototype = {
   /**
    * @see amIWebInstallListener.idl
    */
-  onWebInstallDisabled: function extWebInstallListener_onWebInstallDisabled(aWindow, aUri, aInstalls) {
+  onWebInstallDisabled: function extWebInstallListener_onWebInstallDisabled(aOriginator, aUri, aInstalls) {
     let info = {
-      originatingWindow: aWindow,
+      originator: aOriginator,
       originatingURI: aUri,
       installs: aInstalls,
 
       QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallInfo])
     };
     Services.obs.notifyObservers(info, "addon-install-disabled", null);
   },
 
   /**
    * @see amIWebInstallListener.idl
    */
-  onWebInstallBlocked: function extWebInstallListener_onWebInstallBlocked(aWindow, aUri, aInstalls) {
+  onWebInstallBlocked: function extWebInstallListener_onWebInstallBlocked(aOriginator, aUri, aInstalls) {
     let info = {
-      originatingWindow: aWindow,
+      originator: aOriginator,
       originatingURI: aUri,
       installs: aInstalls,
 
       install: function onWebInstallBlocked_install() {
-        new Installer(this.originatingWindow, this.originatingURI, this.installs);
+        new Installer(this.originator, this.originatingURI, this.installs);
       },
 
       QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallInfo])
     };
     Services.obs.notifyObservers(info, "addon-install-blocked", null);
 
     return false;
   },
 
   /**
    * @see amIWebInstallListener.idl
    */
-  onWebInstallRequested: function extWebInstallListener_onWebInstallRequested(aWindow, aUri, aInstalls) {
-    new Installer(aWindow, aUri, aInstalls);
+  onWebInstallRequested: function extWebInstallListener_onWebInstallRequested(aOriginator, aUri, aInstalls) {
+    new Installer(aOriginator, aUri, aInstalls);
 
     // We start the installs ourself
     return false;
   },
 
   classDescription: "XPI Install Handler",
   contractID: "@mozilla.org/addons/web-install-listener;1",
   classID: Components.ID("{0f38e086-89a3-40a5-8ffc-9b694de1d04a}"),
--- a/toolkit/mozapps/extensions/nsBlocklistService.js
+++ b/toolkit/mozapps/extensions/nsBlocklistService.js
@@ -6,19 +6,26 @@
 
 "use strict";
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-Components.utils.import("resource://gre/modules/AddonManager.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
+try {
+  // AddonManager.jsm doesn't allow itself to be imported in the child
+  // process. We're used in the child process (for now), so guard against
+  // this.
+  Components.utils.import("resource://gre/modules/AddonManager.jsm");
+} catch (e) {
+}
+
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
                                   "resource://gre/modules/UpdateChannel.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "OS",
                                   "resource://gre/modules/osfile.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
                                   "resource://gre/modules/Task.jsm");
--- a/toolkit/mozapps/extensions/test/browser/browser_bug567127.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_bug567127.js
@@ -68,17 +68,17 @@ WindowOpenListener.prototype = {
     this.closecallback = null;
   }
 };
 
 
 var gInstallNotificationObserver = {
   observe: function(aSubject, aTopic, aData) {
     var installInfo = aSubject.QueryInterface(Ci.amIWebInstallInfo);
-    isnot(installInfo.originatingWindow, null, "Notification should have non-null originatingWindow");
+    isnot(installInfo.originator, null, "Notification should have non-null originator");
     gSawInstallNotification = true;
     Services.obs.removeObserver(this, "addon-install-started");
   }
 };
 
 
 function test_confirmation(aWindow, aExpectedURLs) {
   var list = aWindow.document.getElementById("itemList");
--- a/toolkit/mozapps/extensions/test/browser/browser_dragdrop.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_dragdrop.js
@@ -74,17 +74,17 @@ WindowOpenListener.prototype = {
     this.closecallback = null;
   }
 };
 
 var gSawInstallNotification = false;
 var gInstallNotificationObserver = {
   observe: function(aSubject, aTopic, aData) {
     var installInfo = aSubject.QueryInterface(Ci.amIWebInstallInfo);
-    isnot(installInfo.originatingWindow, null, "Notification should have non-null originatingWindow");
+    isnot(installInfo.originator, null, "Notification should have non-null originator");
     gSawInstallNotification = true;
     Services.obs.removeObserver(this, "addon-install-started");
   }
 };
 
 
 function test() {
   waitForExplicitFinish();
--- a/toolkit/mozapps/extensions/test/mochitest/mochitest.ini
+++ b/toolkit/mozapps/extensions/test/mochitest/mochitest.ini
@@ -1,7 +1,7 @@
 [DEFAULT]
-skip-if = buildapp == 'b2g' || e10s
+skip-if = buildapp == 'b2g'
 support-files =
   file_empty.html
 
 [test_bug609794.html]
 [test_bug887098.html]
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_bug645699.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_bug645699.js
@@ -11,17 +11,17 @@ function test() {
   var pm = Services.perms;
   pm.add(makeURI("http://example.org/"), "install", pm.ALLOW_ACTION);
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.loadURI(TESTROOT + "bug645699.html");
 }
 
 function allow_blocked(installInfo) {
-  is(installInfo.originatingWindow, gBrowser.contentWindow, "Install should have been triggered by the right window");
+  is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
   is(installInfo.originatingURI.spec, gBrowser.currentURI.spec, "Install should have been triggered by the right uri");
   return false;
 }
 
 function confirm_install(window) {
   ok(false, "Should not see the install dialog");
   return false;
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist.js
@@ -12,17 +12,17 @@ function test() {
   var triggers = encodeURIComponent(JSON.stringify({
     "Unsigned XPI": TESTROOT + "unsigned.xpi"
   }));
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
 }
 
 function allow_blocked(installInfo) {
-  is(installInfo.originatingWindow, gBrowser.contentWindow, "Install should have been triggered by the right window");
+  is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
   is(installInfo.originatingURI.spec, gBrowser.currentURI.spec, "Install should have been triggered by the right uri");
   return true;
 }
 
 function confirm_install(window) {
   var items = window.document.getElementById("itemList").childNodes;
   is(items.length, 1, "Should only be 1 item listed in the confirmation dialog");
   is(items[0].name, "XPI Test", "Should have seen the name from the trigger list");
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist2.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist2.js
@@ -13,17 +13,17 @@ function test() {
   var triggers = encodeURIComponent(JSON.stringify({
     "Unsigned XPI": TESTROOT2 + "unsigned.xpi"
   }));
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
 }
 
 function allow_blocked(installInfo) {
-  is(installInfo.originatingWindow, gBrowser.contentWindow, "Install should have been triggered by the right window");
+  is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
   is(installInfo.originatingURI.spec, gBrowser.currentURI.spec, "Install should have been triggered by the right uri");
   return false;
 }
 
 function finish_test() {
   Services.perms.remove("example.org", "install");
 
   gBrowser.removeCurrentTab();
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist4.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist4.js
@@ -12,17 +12,17 @@ function test() {
   var triggers = encodeURIComponent(JSON.stringify({
     "Unsigned XPI": TESTROOT2 + "unsigned.xpi"
   }));
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.loadURI(TESTROOT + "unsigned.xpi", makeURI(TESTROOT2 + "test.html"));
 }
 
 function allow_blocked(installInfo) {
-  is(installInfo.originatingWindow, gBrowser.contentWindow, "Install should have been triggered by the right window");
+  is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
   is(installInfo.originatingURI.spec, TESTROOT2 + "test.html", "Install should have been triggered by the right uri");
   return false;
 }
 
 function finish_test(count) {
   is(count, 0, "No add-ons should have been installed");
   Services.perms.remove("example.com", "install");
 
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist5.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist5.js
@@ -7,17 +7,17 @@ function test() {
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.loadURI(TESTROOT + "startsoftwareupdate.html? " + encodeURIComponent(TESTROOT + "unsigned.xpi"));
 }
 
 function allow_blocked(installInfo) {
-  is(installInfo.originatingWindow, gBrowser.contentWindow, "Install should have been triggered by the right window");
+  is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
   is(installInfo.originatingURI.spec, gBrowser.currentURI.spec, "Install should have been triggered by the right uri");
   return false;
 }
 
 function finish_test(count) {
   is(count, 0, "No add-ons should have been installed");
   gBrowser.removeCurrentTab();
   Harness.finish();
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist6.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist6.js
@@ -7,17 +7,18 @@ function test() {
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.loadURI(TESTROOT + "installchrome.html? " + encodeURIComponent(TESTROOT + "unsigned.xpi"));
 }
 
 function allow_blocked(installInfo) {
-  is(installInfo.originatingWindow, gBrowser.contentWindow, "Install should have been triggered by the right window");
+  // XXX Check this for e10s.
+  is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
   is(installInfo.originatingURI.spec, gBrowser.currentURI.spec, "Install should have been triggered by the right uri");
   return false;
 }
 
 function finish_test(count) {
   is(count, 0, "No add-ons should have been installed");
   gBrowser.removeCurrentTab();
   Harness.finish();