Bug 1291641 - Make the Pocket system add-on as e10s compatible. r=mixedpuppy
authorMark Banner <standard8@mozilla.com>
Thu, 18 Aug 2016 13:59:59 +0100
changeset 338525 e1fae5d4806772dbce437ebe2c1862c9a447061b
parent 338524 c9b10a88352d728d13ea0d40c92de6b451a0c516
child 338526 3da4d64410c002418eab4b025dfb24a6f4f57fd6
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-esr52@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmixedpuppy
bugs1291641
milestone51.0a1
Bug 1291641 - Make the Pocket system add-on as e10s compatible. r=mixedpuppy Move the about: handler registration into the content process, and set the flag on the add-on. MozReview-Commit-ID: Ken10jJH9o8
browser/extensions/pocket/bootstrap.js
browser/extensions/pocket/content/AboutPocket.jsm
browser/extensions/pocket/content/pocket-content-process.js
browser/extensions/pocket/install.rdf.in
--- a/browser/extensions/pocket/bootstrap.js
+++ b/browser/extensions/pocket/bootstrap.js
@@ -17,23 +17,28 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "SocialService",
                                   "resource://gre/modules/SocialService.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode",
                                   "resource://gre/modules/ReaderMode.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Pocket",
                                   "chrome://pocket/content/Pocket.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "AboutPocket",
+                                  "chrome://pocket/content/AboutPocket.jsm");
 XPCOMUtils.defineLazyGetter(this, "gPocketBundle", function() {
   return Services.strings.createBundle("chrome://pocket/locale/pocket.properties");
 });
 XPCOMUtils.defineLazyGetter(this, "gPocketStyleURI", function() {
   return Services.io.newURI("chrome://pocket/skin/pocket.css", null, null);
 });
 
+// Due to bug 1051238 frame scripts are cached forever, so we can't update them
+// as a restartless add-on. The Math.random() is the work around for this.
+const PROCESS_SCRIPT = "chrome://pocket/content/pocket-content-process.js?" + Math.random();
 
 const PREF_BRANCH = "extensions.pocket.";
 const PREFS = {
   enabled: true, // bug 1229937, figure out ui tour support
   api: "api.getpocket.com",
   site: "getpocket.com",
   oAuthConsumerKey: "40249-e88c401e1b1f2242d9e441c4"
 };
@@ -62,73 +67,16 @@ function setDefaultPrefs() {
 function createElementWithAttrs(document, type, attrs) {
   let element = document.createElement(type);
   Object.keys(attrs).forEach(function (attr) {
     element.setAttribute(attr, attrs[attr]);
   })
   return element;
 }
 
-XPCOMUtils.defineLazyGetter(this, "AboutSaved", function() {
-  return new PocketAboutPage("chrome://pocket/content/panels/saved.html",
-                             "pocket-saved",
-                             "{3e759f54-37af-7843-9824-f71b5993ceed}",
-                             "About Pocket Saved");
-});
-
-XPCOMUtils.defineLazyGetter(this, "AboutSignup", function() {
-  return new PocketAboutPage("chrome://pocket/content/panels/signup.html",
-                             "pocket-signup",
-                             "{8548329d-00c4-234e-8f17-75026db3b56e}",
-                             "About Pocket Signup");
-});
-
-
-function PocketAboutPage(chromeURL, aboutHost, classID, description) {
-  this.chromeURL = chromeURL;
-  this.aboutHost = aboutHost;
-  this.classID = Components.ID(classID);
-  this.description = description;
-}
-PocketAboutPage.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
-  getURIFlags: function(aURI) {
-    return Ci.nsIAboutModule.ALLOW_SCRIPT |
-           Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT |
-           Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT;
-  },
-
-  newChannel: function(aURI, aLoadInfo) {
-    let newURI = Services.io.newURI(this.chromeURL, null, null);
-    let channel = Services.io.newChannelFromURIWithLoadInfo(newURI,
-                                                            aLoadInfo);
-    channel.originalURI = aURI;
-    return channel;
-  },
-
-  createInstance: function(outer, iid) {
-    if (outer != null) {
-      throw Cr.NS_ERROR_NO_AGGREGATION;
-    }
-    return this.QueryInterface(iid);
-  },
-
-  register: function() {
-    Cm.QueryInterface(Ci.nsIComponentRegistrar).registerFactory(
-      this.classID, this.description,
-      "@mozilla.org/network/protocol/about;1?what=" + this.aboutHost, this);
-  },
-
-  unregister: function() {
-    Cm.QueryInterface(Ci.nsIComponentRegistrar).unregisterFactory(
-      this.classID, this);
-  }
-};
-
-
 function CreatePocketWidget(reason) {
   let id = "pocket-button"
   let widget = CustomizableUI.getWidget(id);
   // The widget is only null if we've created then destroyed the widget.
   // Once we've actually called createWidget the provider will be set to
   // PROVIDER_API.
   if (widget && widget.provider == CustomizableUI.PROVIDER_API)
     return;
@@ -360,30 +308,36 @@ function pktUIGetter(prop, window) {
 
 var PocketOverlay = {
   startup: function(reason) {
     let styleSheetService = Cc["@mozilla.org/content/style-sheet-service;1"]
                               .getService(Ci.nsIStyleSheetService);
     this._sheetType = styleSheetService.AUTHOR_SHEET;
     this._cachedSheet = styleSheetService.preloadSheet(gPocketStyleURI,
                                                        this._sheetType);
-    AboutSaved.register();
-    AboutSignup.register();
+    Services.ppmm.loadProcessScript(PROCESS_SCRIPT, true);
     PocketReader.startup();
     CustomizableUI.addListener(this);
     CreatePocketWidget(reason);
     PocketContextMenu.init();
 
     for (let win of CustomizableUI.windows) {
       this.onWindowOpened(win);
     }
   },
   shutdown: function(reason) {
-    AboutSaved.unregister();
-    AboutSignup.unregister();
+    let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
+                 .getService(Ci.nsIMessageBroadcaster);
+    ppmm.broadcastAsyncMessage("PocketShuttingDown");
+    // Although the ppmm loads the scripts into the chrome process as well,
+    // we need to manually unregister here anyway to ensure these aren't part
+    // of the chrome process and avoid errors.
+    AboutPocket.aboutSaved.unregister();
+    AboutPocket.aboutSignup.unregister();
+
     CustomizableUI.removeListener(this);
     for (let window of CustomizableUI.windows) {
       for (let id of ["panelMenu_pocket", "menu_pocket", "BMB_pocket",
                       "panelMenu_pocketSeparator", "menu_pocketSeparator",
                       "BMB_pocketSeparator"]) {
         let element = window.document.getElementById(id);
         if (element)
           element.remove();
new file mode 100644
--- /dev/null
+++ b/browser/extensions/pocket/content/AboutPocket.jsm
@@ -0,0 +1,93 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+const { interfaces: Ci, results: Cr, manager: Cm, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+// See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
+const PREF_LOG_LEVEL = "loop.debug.loglevel";
+
+XPCOMUtils.defineLazyGetter(this, "log", () => {
+  let ConsoleAPI = Cu.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
+  let consoleOptions = {
+    maxLogLevelPref: PREF_LOG_LEVEL,
+    prefix: "Loop"
+  };
+  return new ConsoleAPI(consoleOptions);
+});
+
+
+function AboutPage(chromeURL, aboutHost, classID, description, uriFlags) {
+  this.chromeURL = chromeURL;
+  this.aboutHost = aboutHost;
+  this.classID = Components.ID(classID);
+  this.description = description;
+  this.uriFlags = uriFlags;
+}
+
+AboutPage.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
+  getURIFlags: function(aURI) { // eslint-disable-line no-unused-vars
+    return this.uriFlags;
+  },
+
+  newChannel: function(aURI, aLoadInfo) {
+    let newURI = Services.io.newURI(this.chromeURL, null, null);
+    let channel = Services.io.newChannelFromURIWithLoadInfo(newURI,
+                                                            aLoadInfo);
+    channel.originalURI = aURI;
+
+    if (this.uriFlags & Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT) {
+      let principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(aURI);
+      channel.owner = principal;
+    }
+    return channel;
+  },
+
+  createInstance: function(outer, iid) {
+    if (outer !== null) {
+      throw Cr.NS_ERROR_NO_AGGREGATION;
+    }
+    return this.QueryInterface(iid);
+  },
+
+  register: function() {
+    Cm.QueryInterface(Ci.nsIComponentRegistrar).registerFactory(
+      this.classID, this.description,
+      "@mozilla.org/network/protocol/about;1?what=" + this.aboutHost, this);
+  },
+
+  unregister: function() {
+    Cm.QueryInterface(Ci.nsIComponentRegistrar).unregisterFactory(
+      this.classID, this);
+  }
+};
+
+/* exported AboutPocket */
+var AboutPocket = {};
+
+XPCOMUtils.defineLazyGetter(AboutPocket, "aboutSaved", () =>
+  new AboutPage("chrome://pocket/content/panels/saved.html",
+                "pocket-saved",
+                "{3e759f54-37af-7843-9824-f71b5993ceed}",
+                "About Pocket Saved",
+                Ci.nsIAboutModule.ALLOW_SCRIPT |
+                Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT |
+                Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT)
+);
+
+XPCOMUtils.defineLazyGetter(AboutPocket, "aboutSignup", () =>
+  new AboutPage("chrome://pocket/content/panels/signup.html",
+                "pocket-signup",
+                "{8548329d-00c4-234e-8f17-75026db3b56e}",
+                "About Pocket Signup",
+                Ci.nsIAboutModule.ALLOW_SCRIPT |
+                Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT |
+                Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT)
+);
+
+this.EXPORTED_SYMBOLS = ["AboutPocket"];
new file mode 100644
--- /dev/null
+++ b/browser/extensions/pocket/content/pocket-content-process.js
@@ -0,0 +1,54 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// This file is loaded as a process script, it will be loaded in the parent
+// process as well as all content processes.
+
+const { utils: Cu } = Components;
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("chrome://pocket/content/AboutPocket.jsm");
+
+function AboutPocketChildListener() {
+}
+AboutPocketChildListener.prototype = {
+  onStartup: function onStartup() {
+
+    // Only do this in content processes since, as the broadcaster of this
+    // message, the parent process doesn't also receive it.  We handlers
+    // the shutting down separately.
+    if (Services.appinfo.processType ==
+        Services.appinfo.PROCESS_TYPE_CONTENT) {
+
+      Services.cpmm.addMessageListener("PocketShuttingDown", this, true);
+    }
+
+    AboutPocket.aboutSaved.register();
+    AboutPocket.aboutSignup.register();
+  },
+
+  onShutdown: function onShutdown() {
+    AboutPocket.aboutSignup.unregister();
+    AboutPocket.aboutSaved.unregister();
+
+    Services.cpmm.removeMessageListener("PocketShuttingDown", this);
+    Cu.unload("chrome://pocket/content/AboutPocket.jsm");
+  },
+
+  receiveMessage: function receiveMessage(message) {
+    switch (message.name) {
+      case "PocketShuttingDown":
+        this.onShutdown();
+        break;
+      default:
+        break;
+    }
+
+    return;
+  }
+};
+
+const listener = new AboutPocketChildListener();
+listener.onStartup();
--- a/browser/extensions/pocket/install.rdf.in
+++ b/browser/extensions/pocket/install.rdf.in
@@ -8,16 +8,17 @@
 <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
      xmlns:em="http://www.mozilla.org/2004/em-rdf#">
 
   <Description about="urn:mozilla:install-manifest">
     <em:id>firefox@getpocket.com</em:id>
     <em:version>1.0.4</em:version>
     <em:type>2</em:type>
     <em:bootstrap>true</em:bootstrap>
+    <em:multiprocessCompatible>true</em:multiprocessCompatible>
 
     <!-- Target Application this theme can install into,
         with minimum and maximum supported versions. -->
     <em:targetApplication>
       <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
         <em:minVersion>@MOZ_APP_VERSION@</em:minVersion>
         <em:maxVersion>@MOZ_APP_MAXVERSION@</em:maxVersion>