Bug 1287007 - Use child's Extension instead of the process' draft
authorRob Wu <rob@robwu.nl>
Tue, 06 Sep 2016 15:31:33 -0700
changeset 428434 a14afbabb0f8454e01c66e6bd70530a1083ccd57
parent 428433 88fe80a6f328e5f7fdd75de4a50aa704d3cc6a84
child 428435 2cb89c1b0f273070d2279d94aa074507faeb576a
push id33305
push userbmo:rob@robwu.nl
push dateSun, 23 Oct 2016 20:56:25 +0000
bugs1287007
milestone52.0a1
Bug 1287007 - Use child's Extension instead of the process' MozReview-Commit-ID: 9o8tOuUbchn
toolkit/components/extensions/Extension.jsm
toolkit/components/extensions/ExtensionChild.jsm
toolkit/components/extensions/ExtensionContent.jsm
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -1159,18 +1159,16 @@ this.Extension = class extends Extension
       delete addonData.cleanupFile;
     }
 
     this.addonData = addonData;
     this.id = addonData.id;
     this.baseURI = NetUtil.newURI(this.getURL("")).QueryInterface(Ci.nsIURL);
     this.principal = this.createPrincipal();
 
-    this.views = new Set();
-
     this.onStartup = null;
 
     this.hasShutdown = false;
     this.onShutdown = new Set();
 
     this.uninstallURL = null;
 
     this.apis = [];
--- a/toolkit/components/extensions/ExtensionChild.jsm
+++ b/toolkit/components/extensions/ExtensionChild.jsm
@@ -39,18 +39,16 @@ var {
   SchemaAPIManager,
 } = ExtensionUtils;
 
 // There is a circular dependency between Extension.jsm and us.
 // Long-term this file should not reference Extension.jsm (because they would
 // live in different processes), but for now use lazy getters.
 XPCOMUtils.defineLazyGetter(this, "findPathInObject",
   () => Cu.import("resource://gre/modules/Extension.jsm", {}).findPathInObject);
-XPCOMUtils.defineLazyGetter(this, "GlobalManager",
-  () => Cu.import("resource://gre/modules/Extension.jsm", {}).GlobalManager);
 XPCOMUtils.defineLazyGetter(this, "ParentAPIManager",
   () => Cu.import("resource://gre/modules/Extension.jsm", {}).ParentAPIManager);
 
 var apiManager = new class extends SchemaAPIManager {
   constructor() {
     super("addon");
     this.initialized = false;
   }
@@ -120,27 +118,31 @@ class WannabeChildAPIManager extends Chi
       // will be available, but no actual implementation is given.
       // You should either provide an implementation or rewrite the JSON schema.
     }
 
     return super.getFallbackImplementation(namespace, name);
   }
 }
 
-// An extension page is an execution context for any extension content
-// that runs in the chrome process. It's used for background pages
-// (viewType="background"), popups (viewType="popup"), and any extension
-// content loaded into browser tabs (viewType="tab").
-//
-// |params| is an object with the following properties:
-// |viewType| is one of "background", "popup", or "tab".
-// |contentWindow| is the DOM window the content runs in.
-// |uri| is the URI of the content (optional).
-// |tabId| is the tab's ID, used if viewType is "tab".
 class ExtensionContext extends BaseContext {
+  /**
+   * This ExtensionContext represents a privileged addon execution environment
+   * that has full access to the WebExtensions APIs (provided that the correct
+   * permissions have been requested).
+   *
+   * @param {BrowserExtensionContent} extension This context's owner.
+   * @param {object} params
+   * @param {nsIDOMWindow} params.contentWindow The window where the addon runs.
+   * @param {string} params.viewType One of "background", "popup" or "tab".
+   *     "background" and "tab" are used by `browser.extension.getViews`.
+   *     "popup" is only used internally to identify page action and browser
+   *     action popups and options_ui pages.
+   * @param {number} [params.tabId] This tab's ID, used if viewType is "tab".
+   */
   constructor(extension, params) {
     super("addon_child", extension);
     if (Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_DEFAULT) {
       // This check is temporary. It should be removed once the proxy creation
       // is asynchronous.
       throw new Error("ExtensionContext cannot be created in child processes");
     }
 
@@ -357,25 +359,21 @@ this.ExtensionChild = {
   uninit(global) {
     this.contentGlobals.get(global).uninit();
     this.contentGlobals.delete(global);
   },
 
   /**
    * Create a privileged context at document-element-inserted.
    *
-   * @param {Extension|BrowserExtensionContent} extension
+   * @param {BrowserExtensionContent} extension
    *     The extension for which the context should be created.
    * @param {nsIDOMWindow} contentWindow The global of the page.
    */
   createExtensionContext(extension, contentWindow) {
-    // TODO(robwu): Remove dependencies on the bloated Extension from
-    // Extension.jsm and use the thin BrowserExtensionContent from
-    // ExtensionContent.jsm instead.
-    extension = GlobalManager.extensionMap.get(extension.id);
     let windowId = getInnerWindowID(contentWindow);
     let context = this.extensionContexts.get(windowId);
     if (context) {
       if (context.extension !== extension) {
         // Oops. This should never happen.
         Cu.reportError("A different extension context already exists in this frame!");
       } else {
         // This should not happen either.
--- a/toolkit/components/extensions/ExtensionContent.jsm
+++ b/toolkit/components/extensions/ExtensionContent.jsm
@@ -697,16 +697,19 @@ function BrowserExtensionContent(data) {
   this.whiteListedHosts = new MatchPattern(data.whiteListedHosts);
   this.permissions = data.permissions;
 
   this.localeData = new LocaleData(data.localeData);
 
   this.manifest = data.manifest;
   this.baseURI = Services.io.newURI(data.baseURL, null, null);
 
+  // Only used in addon processes.
+  this.views = new Set();
+
   let uri = Services.io.newURI(data.resourceURL, null, null);
 
   if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
     // Extension.jsm takes care of this in the parent.
     ExtensionManagement.startupExtension(this.uuid, uri, this);
   }
 }
 
@@ -721,16 +724,20 @@ BrowserExtensionContent.prototype = {
     return this.localeData.localizeMessage(...args);
   },
 
   localize(...args) {
     return this.localeData.localize(...args);
   },
 
   hasPermission(perm) {
+    let match = /^manifest:(.*)/.exec(perm);
+    if (match) {
+      return this.manifest[match[1]] != null;
+    }
     return this.permissions.has(perm);
   },
 };
 
 ExtensionManager = {
   // Map[extensionId, BrowserExtensionContent]
   extensions: new Map(),