Bug 1385880: Part 1 - Remove WebExtensionBootstrap.js. r?aswan draft
authorKris Maglione <maglione.k@gmail.com>
Fri, 04 Aug 2017 13:08:22 -0700
changeset 621435 9caccedfeacd49c45505cfb8a0e0c1d911d9d6b7
parent 621434 acb409fe157726bddde7afade7cfcc6184b0b37c
child 621436 bdee806645c856a2d2b3b433e6ccbbc6d6b1530a
push id72378
push usermaglione.k@gmail.com
push dateFri, 04 Aug 2017 20:22:11 +0000
reviewersaswan
bugs1385880
milestone57.0a1
Bug 1385880: Part 1 - Remove WebExtensionBootstrap.js. r?aswan MozReview-Commit-ID: X4JoEC61TF
toolkit/components/extensions/Extension.jsm
toolkit/mozapps/extensions/AddonManager.jsm
toolkit/mozapps/extensions/internal/WebExtensionBootstrap.js
toolkit/mozapps/extensions/internal/XPIProvider.jsm
toolkit/mozapps/extensions/internal/moz.build
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -42,16 +42,18 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Services.jsm");
 
 /* globals processCount */
 
 XPCOMUtils.defineLazyPreferenceGetter(this, "processCount", "dom.ipc.processCount.extension");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "AddonManagerPrivate",
+                                  "resource://gre/modules/AddonManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown",
                                   "resource://gre/modules/AsyncShutdown.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionAPIs",
                                   "resource://gre/modules/ExtensionAPI.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionCommon",
                                   "resource://gre/modules/ExtensionCommon.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionPermissions",
                                   "resource://gre/modules/ExtensionPermissions.jsm");
@@ -745,16 +747,46 @@ this.ExtensionData = class {
     return results[0];
   }
 };
 
 const PROXIED_EVENTS = new Set(["test-harness-message", "add-permissions", "remove-permissions"]);
 
 const shutdownPromises = new Map();
 
+class BootstrapScope {
+  install(data, reason) {}
+  uninstall(data, reason) {}
+
+  startup(data, reason) {
+    this.extension = new Extension(data, this.BOOTSTRAP_REASON_TO_STRING_MAP[reason]);
+    this.extension.startup();
+  }
+
+  shutdown(data, reason) {
+    this.extension.shutdown(this.BOOTSTRAP_REASON_TO_STRING_MAP[reason]);
+    this.extension = null;
+  }
+}
+
+XPCOMUtils.defineLazyGetter(BootstrapScope.prototype, "BOOTSTRAP_REASON_TO_STRING_MAP", () => {
+  const {BOOTSTRAP_REASONS} = AddonManagerPrivate;
+
+  return Object.freeze({
+    [BOOTSTRAP_REASONS.APP_STARTUP]: "APP_STARTUP",
+    [BOOTSTRAP_REASONS.APP_SHUTDOWN]: "APP_SHUTDOWN",
+    [BOOTSTRAP_REASONS.ADDON_ENABLE]: "ADDON_ENABLE",
+    [BOOTSTRAP_REASONS.ADDON_DISABLE]: "ADDON_DISABLE",
+    [BOOTSTRAP_REASONS.ADDON_INSTALL]: "ADDON_INSTALL",
+    [BOOTSTRAP_REASONS.ADDON_UNINSTALL]: "ADDON_UNINSTALL",
+    [BOOTSTRAP_REASONS.ADDON_UPGRADE]: "ADDON_UPGRADE",
+    [BOOTSTRAP_REASONS.ADDON_DOWNGRADE]: "ADDON_DOWNGRADE",
+  });
+});
+
 // We create one instance of this class per extension. |addonData|
 // comes directly from bootstrap.js when initializing.
 this.Extension = class extends ExtensionData {
   constructor(addonData, startupReason) {
     super(addonData.resourceURI);
 
     this.uuid = UUIDMap.get(addonData.id);
     this.instanceId = getUniqueId();
@@ -835,16 +867,20 @@ this.Extension = class extends Extension
             .filter(host => !origins.includes(host.pattern)));
 
       this.policy.permissions = Array.from(this.permissions);
       this.policy.allowedOrigins = this.whiteListedHosts;
     });
     /* eslint-enable mozilla/balanced-listeners */
   }
 
+  static getBootstrapScope(id, file) {
+    return new BootstrapScope();
+  }
+
   get groupFrameLoader() {
     let frameLoader = this._backgroundPageFrameLoader;
     for (let view of this.views) {
       if (view.viewType === "background" && view.xulBrowser) {
         return view.xulBrowser.frameLoader;
       }
       if (!frameLoader && view.xulBrowser) {
         frameLoader = view.xulBrowser.frameLoader;
--- a/toolkit/mozapps/extensions/AddonManager.jsm
+++ b/toolkit/mozapps/extensions/AddonManager.jsm
@@ -3170,16 +3170,21 @@ this.AddonManagerPrivate = {
   AddonAuthor,
 
   AddonScreenshot,
 
   AddonCompatibilityOverride,
 
   AddonType,
 
+  get BOOTSTRAP_REASONS() {
+    return AddonManagerInternal._getProviderByName("XPIProvider")
+            .BOOTSTRAP_REASONS;
+  },
+
   recordTimestamp(name, value) {
     AddonManagerInternal.recordTimestamp(name, value);
   },
 
   _simpleMeasures: {},
   recordSimpleMeasure(name, value) {
     this._simpleMeasures[name] = value;
   },
deleted file mode 100644
--- a/toolkit/mozapps/extensions/internal/WebExtensionBootstrap.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/* 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";
-
-/* exported startup, shutdown, install, uninstall */
-
-Components.utils.import("resource://gre/modules/Extension.jsm");
-
-var extension;
-
-const BOOTSTRAP_REASON_TO_STRING_MAP = {
-  [this.APP_STARTUP]: "APP_STARTUP",
-  [this.APP_SHUTDOWN]: "APP_SHUTDOWN",
-  [this.ADDON_ENABLE]: "ADDON_ENABLE",
-  [this.ADDON_DISABLE]: "ADDON_DISABLE",
-  [this.ADDON_INSTALL]: "ADDON_INSTALL",
-  [this.ADDON_UNINSTALL]: "ADDON_UNINSTALL",
-  [this.ADDON_UPGRADE]: "ADDON_UPGRADE",
-  [this.ADDON_DOWNGRADE]: "ADDON_DOWNGRADE",
-};
-
-function install(data, reason) {
-}
-
-function startup(data, reason) {
-  extension = new Extension(data, BOOTSTRAP_REASON_TO_STRING_MAP[reason]);
-  extension.startup();
-}
-
-function shutdown(data, reason) {
-  extension.shutdown(BOOTSTRAP_REASON_TO_STRING_MAP[reason]);
-  extension = null;
-}
-
-function uninstall(data, reason) {
-}
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -20,16 +20,18 @@ Cu.import("resource://gre/modules/AddonM
 XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository",
                                   "resource://gre/modules/addons/AddonRepository.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AddonSettings",
                                   "resource://gre/modules/addons/AddonSettings.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
                                   "resource://gre/modules/AppConstants.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ChromeManifestParser",
                                   "resource://gre/modules/ChromeManifestParser.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Extension",
+                                  "resource://gre/modules/Extension.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
                                   "resource://gre/modules/LightweightThemeManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Locale",
                                   "resource://gre/modules/Locale.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ZipUtils",
                                   "resource://gre/modules/ZipUtils.jsm");
@@ -1794,16 +1796,18 @@ this.XPIStates = {
   },
 };
 
 this.XPIProvider = {
   get name() {
     return "XPIProvider";
   },
 
+  BOOTSTRAP_REASONS: Object.freeze(BOOTSTRAP_REASONS),
+
   // An array of known install locations
   installLocations: null,
   // A dictionary of known install locations by name
   installLocationsByName: null,
   // An array of currently active AddonInstalls
   installs: null,
   // The default skin for the application
   defaultSkin: "classic/1.0",
@@ -4222,47 +4226,49 @@ this.XPIProvider = {
         new Cu.Sandbox(principal, { sandboxName: aFile.path,
                                     wantGlobalProperties: ["indexedDB"],
                                     addonId: aId,
                                     metadata: { addonID: aId } });
       logger.error("Attempted to load bootstrap scope from missing directory " + aFile.path);
       return;
     }
 
-    let uri = getURIForResourceInFile(aFile, "bootstrap.js").spec;
-    if (aType == "dictionary")
-      uri = "resource://gre/modules/addons/SpellCheckDictionaryBootstrap.js"
-    else if (isWebExtension(aType))
-      uri = "resource://gre/modules/addons/WebExtensionBootstrap.js"
-    else if (aType == "apiextension")
-      uri = "resource://gre/modules/addons/APIExtensionBootstrap.js"
-
-    activeAddon.bootstrapScope =
-      new Cu.Sandbox(principal, { sandboxName: uri,
-                                  wantGlobalProperties: ["indexedDB"],
-                                  addonId: aId,
-                                  metadata: { addonID: aId, URI: uri } });
-
-    try {
-      // Copy the reason values from the global object into the bootstrap scope.
-      for (let name in BOOTSTRAP_REASONS)
-        activeAddon.bootstrapScope[name] = BOOTSTRAP_REASONS[name];
-
-      // Add other stuff that extensions want.
-      Object.assign(activeAddon.bootstrapScope, {Worker, ChromeWorker});
-
-      // Define a console for the add-on
-      XPCOMUtils.defineLazyGetter(
-        activeAddon.bootstrapScope, "console",
-        () => new ConsoleAPI({ consoleID: "addon/" + aId }));
-
-      activeAddon.bootstrapScope.__SCRIPT_URI_SPEC__ = uri;
-      Services.scriptloader.loadSubScript(uri, activeAddon.bootstrapScope);
-    } catch (e) {
-      logger.warn("Error loading bootstrap.js for " + aId, e);
+    if (isWebExtension(aType)) {
+      activeAddon.bootstrapScope = Extension.getBootstrapScope(aId, aFile);
+    } else {
+      let uri = getURIForResourceInFile(aFile, "bootstrap.js").spec;
+      if (aType == "dictionary")
+        uri = "resource://gre/modules/addons/SpellCheckDictionaryBootstrap.js"
+      else if (aType == "apiextension")
+        uri = "resource://gre/modules/addons/APIExtensionBootstrap.js"
+
+      activeAddon.bootstrapScope =
+        new Cu.Sandbox(principal, { sandboxName: uri,
+                                    wantGlobalProperties: ["indexedDB"],
+                                    addonId: aId,
+                                    metadata: { addonID: aId, URI: uri } });
+
+      try {
+        // Copy the reason values from the global object into the bootstrap scope.
+        for (let name in BOOTSTRAP_REASONS)
+          activeAddon.bootstrapScope[name] = BOOTSTRAP_REASONS[name];
+
+        // Add other stuff that extensions want.
+        Object.assign(activeAddon.bootstrapScope, {Worker, ChromeWorker});
+
+        // Define a console for the add-on
+        XPCOMUtils.defineLazyGetter(
+          activeAddon.bootstrapScope, "console",
+          () => new ConsoleAPI({ consoleID: "addon/" + aId }));
+
+        activeAddon.bootstrapScope.__SCRIPT_URI_SPEC__ = uri;
+        Services.scriptloader.loadSubScript(uri, activeAddon.bootstrapScope);
+      } catch (e) {
+        logger.warn("Error loading bootstrap.js for " + aId, e);
+      }
     }
 
     // Notify the BrowserToolboxProcess that a new addon has been loaded.
     let wrappedJSObject = { id: aId, options: { global: activeAddon.bootstrapScope }};
     Services.obs.notifyObservers({ wrappedJSObject }, "toolbox-update-addon-options");
   },
 
   /**
@@ -4335,18 +4341,18 @@ this.XPIProvider = {
         aExtraParams.instanceID = this.activeAddons.get(aAddon.id).instanceID;
       }
 
       // Nothing to call for locales
       if (aAddon.type == "locale")
         return;
 
       let method = undefined;
+      let scope = activeAddon.bootstrapScope;
       try {
-        let scope = activeAddon.bootstrapScope;
         method = scope[aMethod] || Cu.evalInSandbox(`${aMethod};`, scope);
       } catch (e) {
         // An exception will be caught if the expected method is not defined.
         // That will be logged below.
       }
 
       // Extensions are automatically deinitialized in the correct order at shutdown.
       if (aMethod == "shutdown" && aReason != BOOTSTRAP_REASONS.APP_SHUTDOWN) {
@@ -4382,17 +4388,17 @@ this.XPIProvider = {
       }
 
       if (!method) {
         logger.warn("Add-on " + aAddon.id + " is missing bootstrap method " + aMethod);
       } else {
         logger.debug("Calling bootstrap method " + aMethod + " on " + aAddon.id + " version " +
                      aAddon.version);
         try {
-          method(params, aReason);
+          method.call(scope, params, aReason);
         } catch (e) {
           logger.warn("Exception running bootstrap method " + aMethod + " on " + aAddon.id, e);
         }
       }
     } finally {
       // Extensions are automatically initialized in the correct order at startup.
       if (aMethod == "startup" && aReason != BOOTSTRAP_REASONS.APP_STARTUP) {
         for (let addon of this.getDependentAddons(aAddon))
--- a/toolkit/mozapps/extensions/internal/moz.build
+++ b/toolkit/mozapps/extensions/internal/moz.build
@@ -11,17 +11,16 @@ EXTRA_JS_MODULES.addons += [
     'AddonUpdateChecker.jsm',
     'APIExtensionBootstrap.js',
     'Content.js',
     'E10SAddonsRollout.jsm',
     'GMPProvider.jsm',
     'LightweightThemeImageOptimizer.jsm',
     'ProductAddonChecker.jsm',
     'SpellCheckDictionaryBootstrap.js',
-    'WebExtensionBootstrap.js',
     'XPIInstall.jsm',
     'XPIProvider.jsm',
     'XPIProviderUtils.js',
 ]
 
 TESTING_JS_MODULES += [
     'AddonTestUtils.jsm',
 ]