Bug 1068087: Switch about:plugins to run remotely. r=mconley
authorDave Townsend <dtownsend@oxymoronical.com>
Thu, 08 Jan 2015 12:40:14 -0800
changeset 233749 9393c7434d4e
parent 233748 1b3657fee5a8
child 233750 dab6b12a0ff6
push id28423
push userphilringnalda@gmail.com
push date2015-03-16 02:35 +0000
treeherdermozilla-central@436686833af0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconley
bugs1068087
milestone39.0a1
Bug 1068087: Switch about:plugins to run remotely. r=mconley
docshell/base/nsAboutRedirector.cpp
toolkit/content/plugins.html
toolkit/mozapps/extensions/AddonManager.jsm
--- a/docshell/base/nsAboutRedirector.cpp
+++ b/docshell/base/nsAboutRedirector.cpp
@@ -38,17 +38,20 @@ static RedirEntry kRedirMap[] = {
   {
     "credits", "http://www.mozilla.org/credits/",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT
   },
   {
     "mozilla", "chrome://global/content/mozilla.xhtml",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT
   },
-  { "plugins", "chrome://global/content/plugins.html", 0 },
+  {
+    "plugins", "chrome://global/content/plugins.html",
+    nsIAboutModule::URI_MUST_LOAD_IN_CHILD
+  },
   { "config", "chrome://global/content/config.xul", 0 },
 #ifdef MOZ_CRASHREPORTER
   { "crashes", "chrome://global/content/crashes.xhtml", 0 },
 #endif
   {
     "logo", "chrome://branding/content/about.png",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT
   },
--- a/toolkit/content/plugins.html
+++ b/toolkit/content/plugins.html
@@ -4,18 +4,16 @@
    - 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/. -->
 
 <html>
 <head>
 <script type="application/javascript">
   "use strict";
 
-  Components.utils.import("resource://gre/modules/AddonManager.jsm");
-
   var Ci = Components.interfaces;
   var strBundleService = Components.classes["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
   var pluginsbundle = strBundleService.createBundle("chrome://global/locale/plugins.properties");
   var regionbundle = strBundleService.createBundle("chrome://global-region/locale/region.properties");
 
   document.writeln("<title>" + pluginsbundle.GetStringFromName("title_label") + "<\/title>");
 </script>
 <link rel="stylesheet" type="text/css" href="chrome://global/content/plugins.css">
@@ -53,17 +51,17 @@
 
    * First, refresh plugins in case anything has been changed recently in
    * prefs: (The "false" argument tells refresh not to reload or activate
    * any plug-ins that would be active otherwise.  In contrast, one would
    * use "true" in the case of ASD instead of restarting)
    */
   navigator.plugins.refresh(false);
 
-  AddonManager.getAddonsByTypes(["plugin"], function (aPlugins) {
+  addMessageListener("PluginList", function({ data: aPlugins }) {
     var fragment = document.createDocumentFragment();
 
     // "Installed plugins"
     var id, label;
     if (aPlugins.length > 0) {
       id = "plugs";
       label = "installedplugins_label";
     } else {
@@ -210,12 +208,14 @@
             mimetypeRow.appendChild(suffixes);
           }
         }
       }
     }
 
     document.getElementById("outside").appendChild(fragment);
   });
+
+  sendAsyncMessage("RequestPlugins");
 </script>
 </div>
 </body>
 </html>
--- a/toolkit/mozapps/extensions/AddonManager.jsm
+++ b/toolkit/mozapps/extensions/AddonManager.jsm
@@ -503,16 +503,17 @@ var gStrictCompatibility = true;
 var gCheckUpdateSecurityDefault = true;
 var gCheckUpdateSecurity = gCheckUpdateSecurityDefault;
 var gUpdateEnabled = true;
 var gAutoUpdateDefault = true;
 var gHotfixID = null;
 var gShutdownBarrier = null;
 var gRepoShutdownState = "";
 var gShutdownInProgress = false;
+var gPluginPageListener = null;
 
 /**
  * This is the real manager, kept here rather than in AddonManager to keep its
  * contents hidden from API users.
  */
 var AddonManagerInternal = {
   managerListeners: [],
   installListeners: [],
@@ -843,16 +844,23 @@ var AddonManagerInternal = {
       }
 
       // If this is a new profile just pretend that there were no changes
       if (appChanged === undefined) {
         for (let type in this.startupChanges)
           delete this.startupChanges[type];
       }
 
+      // Support for remote about:plugins. Note that this module isn't loaded
+      // at the top because Services.appinfo is defined late in tests.
+      Cu.import("resource://gre/modules/RemotePageManager.jsm");
+
+      gPluginPageListener = new RemotePages("about:plugins");
+      gPluginPageListener.addMessageListener("RequestPlugins", this.requestPlugins);
+
       gStartupComplete = true;
       this.recordTimestamp("AMI_startup_end");
     }
     catch (e) {
       logger.error("startup failed", e);
       AddonManagerPrivate.recordException("AMI", "startup failed", e);
     }
 
@@ -1054,16 +1062,18 @@ var AddonManagerInternal = {
     gShutdownInProgress = true;
     // Clean up listeners
     Services.prefs.removeObserver(PREF_EM_CHECK_COMPATIBILITY, this);
     Services.prefs.removeObserver(PREF_EM_STRICT_COMPATIBILITY, this);
     Services.prefs.removeObserver(PREF_EM_CHECK_UPDATE_SECURITY, this);
     Services.prefs.removeObserver(PREF_EM_UPDATE_ENABLED, this);
     Services.prefs.removeObserver(PREF_EM_AUTOUPDATE_DEFAULT, this);
     Services.prefs.removeObserver(PREF_EM_HOTFIX_ID, this);
+    gPluginPageListener.destroy();
+    gPluginPageListener = null;
 
     let savedError = null;
     // Only shut down providers if they've been started.
     if (gStarted) {
       try {
         yield gShutdownBarrier.wait();
       }
       catch(err) {
@@ -1097,16 +1107,34 @@ var AddonManagerInternal = {
     gStartupComplete = false;
     gShutdownBarrier = null;
     gShutdownInProgress = false;
     if (savedError) {
       throw savedError;
     }
   }),
 
+  requestPlugins: function({ target: port }) {
+    // Lists all the properties that plugins.html needs
+    const NEEDED_PROPS = ["name", "pluginLibraries", "pluginFullpath", "version",
+                          "isActive", "blocklistState", "description",
+                          "pluginMimeTypes"];
+    function filterProperties(plugin) {
+      let filtered = {};
+      for (let prop of NEEDED_PROPS) {
+        filtered[prop] = plugin[prop];
+      }
+      return filtered;
+    }
+
+    AddonManager.getAddonsByTypes(["plugin"], function (aPlugins) {
+      port.sendAsyncMessage("PluginList", [filterProperties(p) for (p of aPlugins)]);
+    });
+  },
+
   /**
    * Notified when a preference we're interested in has changed.
    *
    * @see nsIObserver
    */
   observe: function AMI_observe(aSubject, aTopic, aData) {
     switch (aData) {
       case PREF_EM_CHECK_COMPATIBILITY: {