Bug 1484373: Part 12 - Use policy object rather than keeping serialized extension data alive. r=mixedpuppy
authorKris Maglione <maglione.k@gmail.com>
Sat, 18 Aug 2018 00:10:53 -0700
changeset 488326 b88f5fa7dca4ba5cb92d9c905f3e52d043977498
parent 488325 812ae71cea4f9c4971a6ef2b40b64eb26ba1feeb
child 488327 10d2e81f3c8a157151bf5cca7133e65458a859eb
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmixedpuppy
bugs1484373
milestone63.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 1484373: Part 12 - Use policy object rather than keeping serialized extension data alive. r=mixedpuppy Differential Revision: https://phabricator.services.mozilla.com/D3702
toolkit/components/extensions/Extension.jsm
toolkit/components/extensions/ExtensionChild.jsm
toolkit/components/extensions/extension-process-script.js
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -1547,32 +1547,36 @@ class Extension extends ExtensionData {
     return this.manifest.content_security_policy;
   }
 
   get backgroundScripts() {
     return (this.manifest.background &&
             this.manifest.background.scripts);
   }
 
+  get optionalPermissions() {
+    return this.manifest.optional_permissions;
+  }
+
   // Representation of the extension to send to content
   // processes. This should include anything the content process might
   // need.
   serialize() {
     return {
       id: this.id,
       uuid: this.uuid,
       name: this.name,
       contentSecurityPolicy: this.contentSecurityPolicy,
       instanceId: this.instanceId,
       resourceURL: this.resourceURL,
       contentScripts: this.contentScripts,
       webAccessibleResources: this.webAccessibleResources.map(res => res.glob),
       whiteListedHosts: this.whiteListedHosts.patterns.map(pat => pat.pattern),
       permissions: this.permissions,
-      optionalPermissions: this.manifest.optional_permissions,
+      optionalPermissions: this.optionalPermissions,
     };
   }
 
   // Extended serialized data which is only needed in the extensions process,
   // and is never deserialized in web content processes.
   serializeExtended() {
     return {
       backgroundScripts: this.backgroundScripts,
--- a/toolkit/components/extensions/ExtensionChild.jsm
+++ b/toolkit/components/extensions/ExtensionChild.jsm
@@ -589,39 +589,32 @@ class Messenger {
 
 // For test use only.
 var ExtensionManager = {
   extensions: new Map(),
 };
 
 // Represents a browser extension in the content process.
 class BrowserExtensionContent extends EventEmitter {
-  constructor(data) {
+  constructor(policy) {
     super();
 
-    this.data = data;
-    this.id = data.id;
-    this.uuid = data.uuid;
-    this.instanceId = data.instanceId;
+    this.policy = policy;
+    this.instanceId = policy.instanceId;
+    this.optionalPermissions = policy.optionalPermissions;
 
     if (WebExtensionPolicy.isExtensionProcess) {
       Object.assign(this, this.getSharedData("extendedData"));
     }
 
     this.MESSAGE_EMIT_EVENT = `Extension:EmitEvent:${this.instanceId}`;
     Services.cpmm.addMessageListener(this.MESSAGE_EMIT_EVENT, this);
 
-    this.webAccessibleResources = data.webAccessibleResources.map(res => new MatchGlob(res));
-    this.permissions = data.permissions;
-    this.optionalPermissions = data.optionalPermissions;
-
     let restrictSchemes = !this.hasPermission("mozillaAddons");
 
-    this.whiteListedHosts = new MatchPatternSet(data.whiteListedHosts, {restrictSchemes, ignorePath: true});
-
     this.apiManager = this.getAPIManager();
 
     this._manifest = null;
     this._localeData = null;
 
     this.baseURI = Services.io.newURI(`moz-extension://${this.uuid}/`);
     this.baseURL = this.baseURI.spec;
 
@@ -632,60 +625,75 @@ class BrowserExtensionContent extends Ev
     this.views = new Set();
 
     // Only used for devtools views.
     this.devtoolsViews = new Set();
 
     /* eslint-disable mozilla/balanced-listeners */
     this.on("add-permissions", (ignoreEvent, permissions) => {
       if (permissions.permissions.length > 0) {
+        let perms = new Set(this.policy.permissions);
         for (let perm of permissions.permissions) {
-          this.permissions.add(perm);
+          perms.add(perm);
         }
+        this.policy.permissions = perms;
       }
 
       if (permissions.origins.length > 0) {
         let patterns = this.whiteListedHosts.patterns.map(host => host.pattern);
 
-        this.whiteListedHosts = new MatchPatternSet([...patterns, ...permissions.origins],
-                                                    {restrictSchemes, ignorePath: true});
-      }
-
-      if (this.policy) {
-        this.policy.permissions = Array.from(this.permissions);
-        this.policy.allowedOrigins = this.whiteListedHosts;
+        this.policy.allowedOrigins =
+          new MatchPatternSet([...patterns, ...permissions.origins],
+                              {restrictSchemes, ignorePath: true});
       }
     });
 
     this.on("remove-permissions", (ignoreEvent, permissions) => {
       if (permissions.permissions.length > 0) {
+        let perms = new Set(this.policy.permissions);
         for (let perm of permissions.permissions) {
-          this.permissions.delete(perm);
+          perms.delete(perm);
         }
+        this.policy.permissions = perms;
       }
 
       if (permissions.origins.length > 0) {
         let origins = permissions.origins.map(
           origin => new MatchPattern(origin, {ignorePath: true}).pattern);
 
-        this.whiteListedHosts = new MatchPatternSet(
+        this.policy.allowedOrigins = new MatchPatternSet(
           this.whiteListedHosts.patterns
               .filter(host => !origins.includes(host.pattern)));
       }
-
-      if (this.policy) {
-        this.policy.permissions = Array.from(this.permissions);
-        this.policy.allowedOrigins = this.whiteListedHosts;
-      }
     });
     /* eslint-enable mozilla/balanced-listeners */
 
     ExtensionManager.extensions.set(this.id, this);
   }
 
+  get id() {
+    return this.policy.id;
+  }
+
+  get uuid() {
+    return this.policy.mozExtensionHostname;
+  }
+
+  get permissions() {
+    return new Set(this.policy.permissions);
+  }
+
+  get whiteListedHosts() {
+    return this.policy.allowedOrigins;
+  }
+
+  get webAccessibleResources() {
+    return this.policy.webAccessibleResources;
+  }
+
   getSharedData(key, value) {
     return sharedData.get(`extension/${this.id}/${key}`);
   }
 
   get localeData() {
     if (!this._localeData) {
       this._localeData = new LocaleData(this.getSharedData("locales"));
     }
--- a/toolkit/components/extensions/extension-process-script.js
+++ b/toolkit/components/extensions/extension-process-script.js
@@ -38,27 +38,17 @@ function getData(extension, key = "") {
 
 // We need to avoid touching Services.appinfo here in order to prevent
 // the wrong version from being cached during xpcshell test startup.
 // eslint-disable-next-line mozilla/use-services
 const appinfo = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
 const isContentProcess = appinfo.processType == appinfo.PROCESS_TYPE_CONTENT;
 
 var extensions = new DefaultWeakMap(policy => {
-  let data = policy.initData;
-  if (data.serialize) {
-    // We have an actual Extension rather than serialized extension
-    // data, so serialize it now to make sure we have consistent inputs
-    // between parent and child processes.
-    data = data.serialize();
-  }
-
-  let extension = new ExtensionChild.BrowserExtensionContent(data);
-  extension.policy = policy;
-  return extension;
+  return new ExtensionChild.BrowserExtensionContent(policy);
 });
 
 var ExtensionManager;
 
 class ExtensionGlobal {
   constructor(global) {
     this.global = global;
     this.global.addMessageListener("Extension:SetFrameData", this);
@@ -173,17 +163,18 @@ ExtensionManager = {
 
       for (let [scriptId, options] of getData(extension, "contentScripts") || []) {
         const script = new WebExtensionContentScript(policy, options);
         policy.registerContentScript(script);
         registeredContentScripts.set(scriptId, script);
       }
 
       policy.active = true;
-      policy.initData = extension;
+      policy.instanceId = extension.instanceId;
+      policy.optionalPermissions = extension.optionalPermissions;
     }
     return policy;
   },
 
   initExtension(data) {
     if (typeof data === "string") {
       data = getData({id: data});
     }