Bug 1446676: Part 2 - Update non-overlay automation extensions to be bootstrapped. r=Mossop
authorKris Maglione <maglione.k@gmail.com>
Fri, 16 Mar 2018 22:06:22 -0700
changeset 465416 18546e2e45c42258dbedd4819b20c47edd8d9c26
parent 465415 c62d96da27e11e0dcbbeaa07e10495135a51d9db
child 465417 95b7ecfc7fe708eb4e720b0a68b11bf81629e774
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMossop
bugs1446676
milestone61.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 1446676: Part 2 - Update non-overlay automation extensions to be bootstrapped. r=Mossop In order to remove support for non-bootstrapped extensions, the remaining test automation extensions need to be migrated to bootstrapped extensions. These extensions all work by loading a single component, either with a profile-after-change or command line handler. This is a straightforward conversion of those components to bootstrap.js scripts. MozReview-Commit-ID: 5uyNSqRPIVR
services/sync/tps/extensions/tps/bootstrap.js
services/sync/tps/extensions/tps/chrome.manifest
services/sync/tps/extensions/tps/components/tps-cmdline.js
services/sync/tps/extensions/tps/install.rdf
testing/talos/talos/mtio-whitelist.json
testing/talos/talos/pageloader/bootstrap.js
testing/talos/talos/pageloader/chrome.manifest
testing/talos/talos/pageloader/components/tp-cmdline.js
testing/talos/talos/pageloader/install.rdf
testing/talos/talos/startup_test/sessionrestore/addon/SessionRestoreTalosTest.js
testing/talos/talos/startup_test/sessionrestore/addon/bootstrap.js
testing/talos/talos/startup_test/sessionrestore/addon/chrome.manifest
testing/talos/talos/startup_test/sessionrestore/addon/install.rdf
testing/talos/talos/talos-powers/bootstrap.js
testing/talos/talos/talos-powers/chrome.manifest
testing/talos/talos/talos-powers/components/TalosPowersService.js
testing/talos/talos/talos-powers/install.rdf
testing/talos/talos/xtalos/xperf_whitelist.json
tools/quitter/QuitterObserver.js
tools/quitter/bootstrap.js
tools/quitter/chrome.manifest
tools/quitter/install.rdf
tools/quitter/moz.build
tools/quitter/quitter@mozilla.org.xpi
rename from services/sync/tps/extensions/tps/components/tps-cmdline.js
rename to services/sync/tps/extensions/tps/bootstrap.js
--- a/services/sync/tps/extensions/tps/components/tps-cmdline.js
+++ b/services/sync/tps/extensions/tps/bootstrap.js
@@ -1,40 +1,52 @@
 /* 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/. */
 
-const TPS_ID                         = "tps@mozilla.org";
-const TPS_CMDLINE_CONTRACTID         = "@mozilla.org/commandlinehandler/general-startup;1?type=tps";
-const TPS_CMDLINE_CLSID              = Components.ID("{4e5bd3f0-41d3-11df-9879-0800200c9a66}");
-const CATMAN_CONTRACTID              = "@mozilla.org/categorymanager;1";
-const nsISupports                    = Ci.nsISupports;
-
-const nsICategoryManager             = Ci.nsICategoryManager;
-const nsICmdLineHandler              = Ci.nsICmdLineHandler;
-const nsICommandLine                 = Ci.nsICommandLine;
-const nsICommandLineHandler          = Ci.nsICommandLineHandler;
-const nsIComponentRegistrar          = Ci.nsIComponentRegistrar;
-const nsISupportsString              = Ci.nsISupportsString;
-const nsIWindowWatcher               = Ci.nsIWindowWatcher;
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/osfile.jsm");
 
-function TPSCmdLineHandler() {}
+XPCOMUtils.defineLazyServiceGetter(this, "categoryManager",
+                                   "@mozilla.org/categorymanager;1",
+                                   "nsICategoryManager");
+
+const Cm = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+
+const CATMAN_CONTRACTID         = "@mozilla.org/categorymanager;1";
+
+const CATEGORY_NAME = "command-line-handler";
+const CATEGORY_ENTRY = "m-tps";
+
+function TPSCmdLine() {}
 
-TPSCmdLineHandler.prototype = {
-  classDescription: "TPSCmdLineHandler",
-  classID: TPS_CMDLINE_CLSID,
-  contractID: TPS_CMDLINE_CONTRACTID,
+TPSCmdLine.prototype = {
+  factory: XPCOMUtils._getFactory(TPSCmdLine),
+  classDescription: "TPSCmdLine",
+  classID: Components.ID("{4e5bd3f0-41d3-11df-9879-0800200c9a66}"),
+  contractID: "@mozilla.org/commandlinehandler/general-startup;1?type=tps",
+
+  QueryInterface:   XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
 
-  QueryInterface: XPCOMUtils.generateQI([nsISupports,
-                                         nsICommandLineHandler,
-                                         nsICmdLineHandler]),   /* nsISupports */
+  register() {
+    Cm.registerFactory(this.classID, this.classDescription,
+                       this.contractID, this.factory);
+
+    categoryManager.addCategoryEntry(CATEGORY_NAME, CATEGORY_ENTRY,
+                                     this.contractID, false, true);
+  },
+
+  unregister() {
+    categoryManager.deleteCategoryEntry(CATEGORY_NAME, CATEGORY_ENTRY,
+                                        this.contractID, false);
+
+    Cm.unregisterFactory(this.classID, this.factory);
+  },
 
   /* nsICmdLineHandler */
   commandLineArgument: "-tps",
   prefNameForStartup: "general.startup.tps",
   helpText: "Run TPS tests with the given test file.",
   handlesArgs: true,
   defaultArgs: "",
   openWindowWithArgs: true,
@@ -70,78 +82,18 @@ TPSCmdLineHandler.prototype = {
   },
 
   helpInfo: "  --tps <file>              Run TPS tests with the given test file.\n" +
             "  --tpsphase <phase>        Run the specified phase in the TPS test.\n" +
             "  --tpslogfile <file>       Logfile for TPS output.\n" +
             "  --ignore-unused-engines   Don't load engines not used in tests.\n",
 };
 
-
-var TPSCmdLineFactory = {
-  createInstance(outer, iid) {
-    if (outer != null) {
-      throw new Error(Cr.NS_ERROR_NO_AGGREGATION);
-    }
-
-    return new TPSCmdLineHandler().QueryInterface(iid);
-  }
-};
-
-
-var TPSCmdLineModule = {
-  registerSelf(compMgr, fileSpec, location, type) {
-    compMgr = compMgr.QueryInterface(nsIComponentRegistrar);
-
-    compMgr.registerFactoryLocation(TPS_CMDLINE_CLSID,
-                                    "TPS CommandLine Service",
-                                    TPS_CMDLINE_CONTRACTID,
-                                    fileSpec,
-                                    location,
-                                    type);
-
-    var catman = Cc[CATMAN_CONTRACTID].getService(nsICategoryManager);
-    catman.addCategoryEntry("command-line-argument-handlers",
-                            "TPS command line handler",
-                            TPS_CMDLINE_CONTRACTID, true, true);
-    catman.addCategoryEntry("command-line-handler",
-                            "m-tps",
-                            TPS_CMDLINE_CONTRACTID, true, true);
-  },
-
-  unregisterSelf(compMgr, fileSpec, location) {
-    compMgr = compMgr.QueryInterface(nsIComponentRegistrar);
+function startup(data, reason) {
+  TPSCmdLine.prototype.register();
+}
 
-    compMgr.unregisterFactoryLocation(TPS_CMDLINE_CLSID, fileSpec);
-    let catman = Cc[CATMAN_CONTRACTID].getService(nsICategoryManager);
-    catman.deleteCategoryEntry("command-line-argument-handlers",
-                               "TPS command line handler", true);
-    catman.deleteCategoryEntry("command-line-handler",
-                               "m-tps", true);
-  },
-
-  getClassObject(compMgr, cid, iid) {
-    if (cid.equals(TPS_CMDLINE_CLSID)) {
-      return TPSCmdLineFactory;
-    }
-
-    if (!iid.equals(Ci.nsIFactory)) {
-      throw new Error(Cr.NS_ERROR_NOT_IMPLEMENTED);
-    }
+function shutdown(data, reason) {
+  TPSCmdLine.prototype.unregister();
+}
 
-    throw new Error(Cr.NS_ERROR_NO_INTERFACE);
-  },
-
-  canUnload(compMgr) {
-    return true;
-  }
-};
-
-/**
-* XPCOMUtils.generateNSGetFactory was introduced in Mozilla 2 (Firefox 4).
-* XPCOMUtils.generateNSGetModule is for Mozilla 1.9.2 (Firefox 3.6).
-*/
-if (XPCOMUtils.generateNSGetFactory)
-    var NSGetFactory = XPCOMUtils.generateNSGetFactory([TPSCmdLineHandler]);
-
-function NSGetModule(compMgr, fileSpec) {
-  return TPSCmdLineModule;
-}
+function install(data, reason) {}
+function uninstall(data, reason) {}
--- a/services/sync/tps/extensions/tps/chrome.manifest
+++ b/services/sync/tps/extensions/tps/chrome.manifest
@@ -1,5 +1,1 @@
 resource tps resource/
-
-component {4e5bd3f0-41d3-11df-9879-0800200c9a66} components/tps-cmdline.js
-contract @mozilla.org/commandlinehandler/general-startup;1?type=tps {4e5bd3f0-41d3-11df-9879-0800200c9a66}
-category command-line-handler m-tps @mozilla.org/commandlinehandler/general-startup;1?type=tps
--- a/services/sync/tps/extensions/tps/install.rdf
+++ b/services/sync/tps/extensions/tps/install.rdf
@@ -3,16 +3,17 @@
    - 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/. -->
 
 <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>tps@mozilla.org</em:id>
     <em:version>0.5</em:version>
+    <em:bootstrap>true</em:bootstrap>
 
     <em:targetApplication>
       <!-- Firefox -->
       <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
         <em:minVersion>24.0.*</em:minVersion>
         <em:maxVersion>31.0.*</em:maxVersion>
       </Description>
--- a/testing/talos/talos/mtio-whitelist.json
+++ b/testing/talos/talos/mtio-whitelist.json
@@ -118,16 +118,17 @@
  "{profile}\\extensions\\pageloader@mozilla.org": {},
  "{profile}\\extensions\\pageloader@mozilla.org\\chrome\\profiler.js": {},
  "{profile}\\extensions\\pageloader@mozilla.org\\chrome\\talos-content.js": {},
  "{profile}\\extensions\\pageloader@mozilla.org\\chrome\\tscroll.js": {},
  "{profile}\\extensions\\pageloader@mozilla.org\\install.rdf": {},
  "{profile}\\extensions\\pageloader@mozilla.org\\plugins": {},
  "{profile}\\extensions\\pageloader@mozilla.org\\searchplugins": {},
  "{profile}\\extensions\\talos-powers@mozilla.org": {},
+ "{profile}\\extensions\\talos-powers@mozilla.org\\bootstrap.js": {},
  "{profile}\\extensions\\talos-powers@mozilla.org\\chrome.manifest": {},
  "{profile}\\extensions\\talos-powers@mozilla.org\\chrome\\talos-powers-content.js": {},
  "{profile}\\extensions\\talos-powers@mozilla.org\\components\\talospowersservice.js": {},
  "{profile}\\extensions\\talos-powers@mozilla.org\\install.rdf": {},
  "{profile}\\extensions\\talos-powers@mozilla.org\\plugins": {},
  "{profile}\\extensions\\talos-powers@mozilla.org\\searchplugins": {},
  "{profile}\\favicons.sqlite": {},
  "{profile}\\favicons.sqlite-journal": {},
rename from testing/talos/talos/pageloader/components/tp-cmdline.js
rename to testing/talos/talos/pageloader/bootstrap.js
--- a/testing/talos/talos/pageloader/components/tp-cmdline.js
+++ b/testing/talos/talos/pageloader/bootstrap.js
@@ -35,42 +35,52 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 // This only implements nsICommandLineHandler, since it needs
 // to handle multiple arguments.
 
-const TP_CMDLINE_CONTRACTID     = "@mozilla.org/commandlinehandler/general-startup;1?type=tp";
-const TP_CMDLINE_CLSID          = Components.ID("{8AF052F5-8EFE-4359-8266-E16498A82E8B}");
-const CATMAN_CONTRACTID         = "@mozilla.org/categorymanager;1";
-const nsISupports               = Ci.nsISupports;
+ChromeUtils.import("resource://gre/modules/Services.jsm");
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "categoryManager",
+                                   "@mozilla.org/categorymanager;1",
+                                   "nsICategoryManager");
 
-const nsICategoryManager        = Ci.nsICategoryManager;
-const nsICommandLine            = Ci.nsICommandLine;
-const nsICommandLineHandler     = Ci.nsICommandLineHandler;
-const nsIComponentRegistrar     = Ci.nsIComponentRegistrar;
-const nsISupportsString         = Ci.nsISupportsString;
-const nsIWindowWatcher          = Ci.nsIWindowWatcher;
+const Cm = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+
+const CATMAN_CONTRACTID         = "@mozilla.org/categorymanager;1";
+
+const CATEGORY_NAME = "command-line-handler";
+const CATEGORY_ENTRY = "m-tp";
 
-ChromeUtils.import("resource://gre/modules/Services.jsm");
-
-function PageLoaderCmdLineHandler() {}
-PageLoaderCmdLineHandler.prototype =
+function PageLoaderCmdLine() {}
+PageLoaderCmdLine.prototype =
 {
-  /* nsISupports */
-  QueryInterface: function handler_QI(iid) {
-    if (iid.equals(nsISupports))
-      return this;
+  factory: XPCOMUtils._getFactory(PageLoaderCmdLine),
+  classDescription: "Loads pages. Tests them.",
+  classID:          Components.ID("{8AF052F5-8EFE-4359-8266-E16498A82E8B}"),
+  contractID:       "@mozilla.org/commandlinehandler/general-startup;1?type=tp",
+  QueryInterface:   XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
+
+  register() {
+    Cm.registerFactory(this.classID, this.classDescription,
+                       this.contractID, this.factory);
 
-    if (nsICommandLineHandler && iid.equals(nsICommandLineHandler))
-      return this;
+    categoryManager.addCategoryEntry(CATEGORY_NAME, CATEGORY_ENTRY,
+                                     this.contractID, false, true);
+  },
 
-    throw Cr.NS_ERROR_NO_INTERFACE;
+  unregister() {
+    categoryManager.deleteCategoryEntry(CATEGORY_NAME, CATEGORY_ENTRY,
+                                        this.contractID, false);
+
+    Cm.unregisterFactory(this.classID, this.factory);
   },
 
   /* nsICommandLineHandler */
   handle: function handler_handle(cmdLine) {
     var args = {};
 
     var tpmanifest = Services.prefs.getCharPref("talos.tpmanifest", null);
     if (tpmanifest == null) {
@@ -88,67 +98,18 @@ PageLoaderCmdLineHandler.prototype =
     Services.ww.openWindow(null, chromeURL, "_blank",
                             "chrome,dialog=no,all", args);
 
     // Don't pass command line to the default app processor
     cmdLine.preventDefault = true;
   },
 };
 
-
-var PageLoaderCmdLineFactory =
-{
-  createInstance(outer, iid) {
-    if (outer != null) {
-      throw Cr.NS_ERROR_NO_AGGREGATION;
-    }
-
-    return new PageLoaderCmdLineHandler().QueryInterface(iid);
-  }
-};
-
-function NSGetFactory(cid) {
-  if (!cid.equals(TP_CMDLINE_CLSID))
-    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
-
-  return PageLoaderCmdLineFactory;
+function startup(data, reason) {
+  PageLoaderCmdLine.prototype.register();
 }
 
-var PageLoaderCmdLineModule =
-{
-  registerSelf(compMgr, fileSpec, location, type) {
-    compMgr = compMgr.QueryInterface(nsIComponentRegistrar);
-
-    compMgr.registerFactoryLocation(TP_CMDLINE_CLSID,
-                                    "PageLoader CommandLine Service",
-                                    TP_CMDLINE_CONTRACTID,
-                                    fileSpec,
-                                    location,
-                                    type);
-
-    var catman = Cc[CATMAN_CONTRACTID].getService(nsICategoryManager);
-    catman.addCategoryEntry("command-line-handler",
-                            "m-tp",
-                            TP_CMDLINE_CONTRACTID, true, true);
-  },
+function shutdown(data, reason) {
+  PageLoaderCmdLine.prototype.unregister();
+}
 
-  unregisterSelf(compMgr, fileSpec, location) {
-    compMgr = compMgr.QueryInterface(nsIComponentRegistrar);
-
-    compMgr.unregisterFactoryLocation(TP_CMDLINE_CLSID, fileSpec);
-    var catman = Cc[CATMAN_CONTRACTID].getService(nsICategoryManager);
-    catman.deleteCategoryEntry("command-line-handler",
-                               "m-tp", true);
-  },
-
-  getClassObject(compMgr, cid, iid) {
-    return NSGetFactory(cid);
-  },
-
-  canUnload(compMgr) {
-    return true;
-  }
-};
-
-
-function NSGetModule(compMgr, fileSpec) {
-  return PageLoaderCmdLineModule;
-}
+function install(data, reason) {}
+function uninstall(data, reason) {}
--- a/testing/talos/talos/pageloader/chrome.manifest
+++ b/testing/talos/talos/pageloader/chrome.manifest
@@ -1,4 +1,1 @@
 content pageloader chrome/
-component {8AF052F5-8EFE-4359-8266-E16498A82E8B} components/tp-cmdline.js
-contract @mozilla.org/commandlinehandler/general-startup;1?type=tp {8AF052F5-8EFE-4359-8266-E16498A82E8B}
-category command-line-handler m-tp @mozilla.org/commandlinehandler/general-startup;1?type=tp
--- a/testing/talos/talos/pageloader/install.rdf
+++ b/testing/talos/talos/pageloader/install.rdf
@@ -1,15 +1,16 @@
 <?xml version="1.0"?>
 
 <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>pageloader@mozilla.org</em:id>
     <em:version>1.0.32</em:version>
+    <em:bootstrap>true</em:bootstrap>
     <em:targetApplication>
       <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
         <em:minVersion>44.0</em:minVersion>
         <em:maxVersion>*</em:maxVersion>
       </Description>
     </em:targetApplication>
     <!-- Front End MetaData -->
rename from testing/talos/talos/startup_test/sessionrestore/addon/SessionRestoreTalosTest.js
rename to testing/talos/talos/startup_test/sessionrestore/addon/bootstrap.js
--- a/testing/talos/talos/startup_test/sessionrestore/addon/SessionRestoreTalosTest.js
+++ b/testing/talos/talos/startup_test/sessionrestore/addon/bootstrap.js
@@ -11,43 +11,30 @@ ChromeUtils.import("resource://gre/modul
 ChromeUtils.defineModuleGetter(this, "Services",
   "resource://gre/modules/Services.jsm");
 ChromeUtils.defineModuleGetter(this, "setTimeout",
   "resource://gre/modules/Timer.jsm");
 ChromeUtils.defineModuleGetter(this, "StartupPerformance",
   "resource:///modules/sessionstore/StartupPerformance.jsm");
 
 // Observer Service topics.
-const STARTUP_TOPIC = "profile-after-change";
 const WINDOW_READY_TOPIC = "browser-delayed-startup-finished";
 
 // Process Message Manager topics.
 const MSG_REQUEST = "session-restore-test?duration";
 const MSG_PROVIDE = "session-restore-test:duration";
 
-function nsSessionRestoreTalosTest() { }
-
-nsSessionRestoreTalosTest.prototype = {
-  classID: Components.ID("{716346e5-0c45-4aa2-b601-da36f3c74bd8}"),
-
-  _xpcom_factory: XPCOMUtils.generateSingletonFactory(nsSessionRestoreTalosTest),
-
-  // ////////////////////////////////////////////////////////////////////////////
-  // // nsISupports
-
+const sessionRestoreTest = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
 
   // ////////////////////////////////////////////////////////////////////////////
   // // nsIObserver
 
   observe: function DS_observe(aSubject, aTopic, aData) {
     switch (aTopic) {
-      case STARTUP_TOPIC:
-        this.init();
-        break;
       case StartupPerformance.RESTORED_TOPIC:
         this.onReady(true);
         break;
       case WINDOW_READY_TOPIC:
         Services.obs.removeObserver(this, WINDOW_READY_TOPIC);
         this.onWindow(aSubject);
         break;
       default:
@@ -142,12 +129,16 @@ nsSessionRestoreTalosTest.prototype = {
       let url = new URL(args.queryElementAt(0, Ci.nsISupportsString).data);
       queryString = url.search;
     }
 
     win.gBrowser.addTab("chrome://session-restore-test/content/index.html" + queryString);
   }
 };
 
-// //////////////////////////////////////////////////////////////////////////////
-// // Module
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([nsSessionRestoreTalosTest]);
+function startup(data, reason) {
+  sessionRestoreTest.init();
+}
+
+function shutdown(data, reason) {}
+function install(data, reason) {}
+function uninstall(data, reason) {}
--- a/testing/talos/talos/startup_test/sessionrestore/addon/chrome.manifest
+++ b/testing/talos/talos/startup_test/sessionrestore/addon/chrome.manifest
@@ -1,8 +1,1 @@
-# Register a component to be informed of startup. This component can then register
-# itself to watch sessionstore-windows-restored. Once it has observed
-# sessionstore-windows-restored, it will open the webpage with the harness.
-component {716346e5-0c45-4aa2-b601-da36f3c74bd8} SessionRestoreTalosTest.js
-contract @mozilla.org/talos/session-restore-test;1 {716346e5-0c45-4aa2-b601-da36f3c74bd8}
-category profile-after-change nsSessionRestoreTalosTest @mozilla.org/talos/session-restore-test;1
-
 content session-restore-test content/
--- a/testing/talos/talos/startup_test/sessionrestore/addon/install.rdf
+++ b/testing/talos/talos/startup_test/sessionrestore/addon/install.rdf
@@ -1,14 +1,15 @@
 <?xml version="1.0"?><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">
 
 <!-- Required Items -->
 <em:id>session-restore-test-2@mozilla.org</em:id>
 <em:name>Session Restore Startup Performance Test</em:name>
 <em:version>2.0.11</em:version>
+<em:bootstrap>true</em:bootstrap>
 
 <em:targetApplication>
     <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
         <em:minVersion>1.5</em:minVersion>
         <em:maxVersion>*</em:maxVersion>
     </Description>
 </em:targetApplication>
rename from testing/talos/talos/talos-powers/components/TalosPowersService.js
rename to testing/talos/talos/talos-powers/bootstrap.js
--- a/testing/talos/talos/talos-powers/components/TalosPowersService.js
+++ b/testing/talos/talos/talos-powers/bootstrap.js
@@ -3,53 +3,53 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "Services",
   "resource://gre/modules/Services.jsm");
 ChromeUtils.defineModuleGetter(this, "OS",
   "resource://gre/modules/osfile.jsm");
 
+Cu.importGlobalProperties(["TextEncoder"]);
+
+const Cm = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+
 const FRAME_SCRIPT = "chrome://talos-powers/content/talos-powers-content.js";
 
 function TalosPowersService() {
   this.wrappedJSObject = this;
+
+  this.init();
 }
 
 TalosPowersService.prototype = {
+  factory: XPCOMUtils._getFactory(TalosPowersService),
   classDescription: "Talos Powers",
   classID: Components.ID("{f5d53443-d58d-4a2f-8df0-98525d4f91ad}"),
   contractID: "@mozilla.org/talos/talos-powers-service;1",
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
+  QueryInterface: XPCOMUtils.generateQI([]),
+
+  register() {
+    Cm.registerFactory(this.classID, this.classDescription,
+                       this.contractID, this.factory);
 
-  observe(subject, topic, data) {
-    switch (topic) {
-      case "profile-after-change":
-        // Note that this observation is registered in the chrome.manifest
-        // for this add-on.
-        this.init();
-        break;
-      case "xpcom-shutdown":
-        this.uninit();
-        break;
-    }
+    void Cc[this.contractID].getService();
+  },
+
+  unregister() {
+    Cm.unregisterFactory(this.classID, this.factory);
   },
 
   init() {
     Services.mm.loadFrameScript(FRAME_SCRIPT, true);
     Services.mm.addMessageListener("Talos:ForceQuit", this);
     Services.mm.addMessageListener("TalosContentProfiler:Command", this);
     Services.mm.addMessageListener("TalosPowersContent:ForceCCAndGC", this);
     Services.mm.addMessageListener("TalosPowersContent:GetStartupInfo", this);
     Services.mm.addMessageListener("TalosPowers:ParentExec:QueryMsg", this);
-    Services.obs.addObserver(this, "xpcom-shutdown");
-  },
-
-  uninit() {
-    Services.obs.removeObserver(this, "xpcom-shutdown");
   },
 
   receiveMessage(message) {
     switch (message.name) {
       case "Talos:ForceQuit": {
         this.forceQuit(message.data);
         break;
       }
@@ -322,9 +322,17 @@ TalosPowersService.prototype = {
     if (!this.ParentExecServices.hasOwnProperty(command.name))
       throw new Error("TalosPowers:ParentExec: Invalid service '" + command.name + "'");
 
     this.ParentExecServices[command.name](command.data, sendResult, msg.target.ownerGlobal);
   },
 
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TalosPowersService]);
+function startup(data, reason) {
+  TalosPowersService.prototype.register();
+}
+
+function shutdown(data, reason) {
+  TalosPowersService.prototype.unregister();
+}
+function install(data, reason) {}
+function uninstall(data, reason) {}
--- a/testing/talos/talos/talos-powers/chrome.manifest
+++ b/testing/talos/talos/talos-powers/chrome.manifest
@@ -1,5 +1,2 @@
 content talos-powers chrome/
 content talos-powers-content content/ contentaccessible=yes
-component {f5d53443-d58d-4a2f-8df0-98525d4f91ad} components/TalosPowersService.js
-contract @mozilla.org/talos/talos-powers-service;1 {f5d53443-d58d-4a2f-8df0-98525d4f91ad}
-category profile-after-change TalosPowersService @mozilla.org/talos/talos-powers-service;1
--- a/testing/talos/talos/talos-powers/install.rdf
+++ b/testing/talos/talos/talos-powers/install.rdf
@@ -1,15 +1,16 @@
 <?xml version="1.0"?>
 
 <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>talos-powers@mozilla.org</em:id>
     <em:version>1.0.14</em:version>
+    <em:bootstrap>true</em:bootstrap>
     <em:targetApplication>
       <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
         <em:minVersion>44.0</em:minVersion>
         <em:maxVersion>*</em:maxVersion>
       </Description>
     </em:targetApplication>
     <!-- Front End MetaData -->
--- a/testing/talos/talos/xtalos/xperf_whitelist.json
+++ b/testing/talos/talos/xtalos/xperf_whitelist.json
@@ -270,16 +270,22 @@
     "maxbytes": 8192
   },
   "{profile}\\extensions.json": {
     "mincount": 0,
     "maxcount": 4,
     "minbytes": 0,
     "maxbytes": 512
   },
+  "{profile}\\extensions\\pageloader@mozilla.org\\bootstrap.js": {
+    "mincount": 0,
+    "maxcount": 6,
+    "minbytes": 0,
+    "maxbytes": 30000
+  },
   "{profile}\\extensions\\pageloader@mozilla.org\\chrome.manifest": {
     "mincount": 2,
     "maxcount": 2,
     "minbytes": 600,
     "maxbytes": 600
   },
   "{profile}\\extensions\\pageloader@mozilla.org\\chrome\\memory.js": {
     "mincount": 0,
@@ -324,16 +330,22 @@
     "maxbytes": 127000
   },
   "{profile}\\extensions\\pageloader@mozilla.org\\install.rdf": {
     "mincount": 0,
     "maxcount": 2,
     "minbytes": 0,
     "maxbytes": 8192
   },
+  "{profile}\\extensions\\talos-powers@mozilla.org\\bootstrap.js": {
+    "mincount": 0,
+    "maxcount": 6,
+    "minbytes": 0,
+    "maxbytes": 30000
+  },
   "{profile}\\extensions\\talos-powers@mozilla.org\\chrome.manifest": {
     "mincount": 2,
     "maxcount": 2,
     "minbytes": 600,
     "maxbytes": 600
   },
   "{profile}\\extensions\\talos-powers@mozilla.org\\chrome\\talos-powers-content.js": {
     "mincount": 2,
rename from tools/quitter/QuitterObserver.js
rename to tools/quitter/bootstrap.js
--- a/tools/quitter/QuitterObserver.js
+++ b/tools/quitter/bootstrap.js
@@ -1,63 +1,43 @@
 /* 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/. */
 
-ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 const CHILD_SCRIPT = "chrome://quitter/content/contentscript.js";
 
-/* XPCOM gunk */
-function QuitterObserver() {}
-
-QuitterObserver.prototype = {
-  classDescription: "Quitter Observer for use in testing.",
-  classID:          Components.ID("{c235a986-5ac1-4f28-ad73-825dae9bad90}"),
-  contractID:       "@mozilla.org/quitter-observer;1",
-  QueryInterface:   XPCOMUtils.generateQI([Ci.nsIObserver]),
-  _xpcom_categories: [{category: "profile-after-change", service: true }],
-  isFrameScriptLoaded: false,
-
-  observe(aSubject, aTopic, aData) {
-    if (aTopic == "profile-after-change") {
-      this.init();
-    } else if (!this.isFrameScriptLoaded &&
-               aTopic == "chrome-document-global-created") {
-
-      var messageManager = Cc["@mozilla.org/globalmessagemanager;1"].
-                           getService(Ci.nsIMessageBroadcaster);
-      // Register for any messages our API needs us to handle
-      messageManager.addMessageListener("Quitter.Quit", this);
-
-      messageManager.loadFrameScript(CHILD_SCRIPT, true);
-      this.isFrameScriptLoaded = true;
-    } else if (aTopic == "xpcom-shutdown") {
-      this.uninit();
-    }
-  },
-
+const quitterObserver = {
   init() {
-    var obs = Services.obs;
-    obs.addObserver(this, "xpcom-shutdown");
-    obs.addObserver(this, "chrome-document-global-created");
+    Services.mm.addMessageListener("Quitter.Quit", this);
+    Services.mm.loadFrameScript(CHILD_SCRIPT, true);
   },
 
   uninit() {
-    var obs = Services.obs;
-    obs.removeObserver(this, "chrome-document-global-created");
+    Services.obs.removeObserver(this, "chrome-document-global-created");
+    Services.mm.removeMessageListener("Quitter.Quit", this);
+    Services.mm.removeDelayedFrameScript(CHILD_SCRIPT, true);
   },
 
   /**
    * messageManager callback function
    * This will get requests from our API in the window and process them in chrome for it
    **/
   receiveMessage(aMessage) {
     switch (aMessage.name) {
       case "Quitter.Quit":
         Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
         break;
     }
   }
 };
 
-const NSGetFactory = XPCOMUtils.generateNSGetFactory([QuitterObserver]);
+function startup(data, reason) {
+  quitterObserver.init();
+}
+
+function shutdown(data, reason) {
+  quitterObserver.uninit();
+}
+
+function install(data, reason) {}
+function uninstall(data, reason) {}
--- a/tools/quitter/chrome.manifest
+++ b/tools/quitter/chrome.manifest
@@ -1,4 +1,1 @@
-category profile-after-change @mozilla.org/quitter-observer;1 @mozilla.org/quitter-observer;1
-component {c235a986-5ac1-4f28-ad73-825dae9bad90} components/QuitterObserver.js
 content quitter chrome/quitter/content/
-contract @mozilla.org/quitter-observer;1 {c235a986-5ac1-4f28-ad73-825dae9bad90}
--- a/tools/quitter/install.rdf
+++ b/tools/quitter/install.rdf
@@ -1,17 +1,18 @@
 <?xml version="1.0"?>
 
 <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>quitter@mozilla.org</em:id>
-    <em:version>2016.03.10</em:version>
+    <em:version>2018.03.19</em:version>
     <em:type>2</em:type>
+    <em:bootstrap>true</em:bootstrap>
 
     <!-- Target Application this extension can install into,
          with minimum and maximum supported versions. -->
     <em:targetApplication>
       <Description>
         <!-- Firefox -->
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
         <em:minVersion>45</em:minVersion>
--- a/tools/quitter/moz.build
+++ b/tools/quitter/moz.build
@@ -1,21 +1,18 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-EXTRA_COMPONENTS += [
-    'QuitterObserver.js',
-]
-
 XPI_NAME = 'quitter'
 
 JAR_MANIFESTS += ['jar.mn']
 
 USE_EXTENSION_MANIFEST = True
 NO_JS_MANIFEST = True
 
 FINAL_TARGET_FILES += [
+    'bootstrap.js',
     'chrome.manifest',
     'install.rdf',
 ]
index 5d2c0ef6e00658aaef22a5d7ea130f8bf87c8872..9db483065e9639d0eeee270bad7bec356e6ee978
GIT binary patch
literal 7355
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
PfPTL{zo!L}{q+6|P6DnE