Bug 1316396: Part 6 - Use MessageManagerProxy in parent proxy contexts. r?aswan draft
authorKris Maglione <maglione.k@gmail.com>
Thu, 10 Nov 2016 10:55:05 -0800
changeset 437308 a46cfa86ece5520efbeca2416257750f0598d177
parent 437307 8a94dad26f192b08b053eaa6743f8d5a9f8a5f93
child 536610 38ddc3ad9fd73a1d92495bfa25ba01d21665c2d1
push id35381
push usermaglione.k@gmail.com
push dateThu, 10 Nov 2016 18:57:25 +0000
reviewersaswan
bugs1316396
milestone52.0a1
Bug 1316396: Part 6 - Use MessageManagerProxy in parent proxy contexts. r?aswan MozReview-Commit-ID: 1EgmGwzORWC
toolkit/components/extensions/ExtensionParent.jsm
--- a/toolkit/components/extensions/ExtensionParent.jsm
+++ b/toolkit/components/extensions/ExtensionParent.jsm
@@ -29,16 +29,17 @@ Cu.import("resource://gre/modules/Extens
 Cu.import("resource://gre/modules/ExtensionUtils.jsm");
 
 var {
   BaseContext,
   SchemaAPIManager,
 } = ExtensionCommon;
 
 var {
+  MessageManagerProxy,
   SpreadArgs,
   defineLazyGetter,
   findPathInObject,
 } = ExtensionUtils;
 
 const BASE_SCHEMA = "chrome://extensions/content/schemas/manifest.json";
 const CATEGORY_EXTENSION_SCHEMAS = "webextension-schemas";
 const CATEGORY_EXTENSION_SCRIPTS = "webextension-scripts";
@@ -229,62 +230,33 @@ GlobalManager = {
   },
 
   injectInObject(context, isChromeCompat, dest) {
     apiManager.generateAPIs(context, dest);
     SchemaAPIManager.generateAPIs(context, context.extension.apis, dest);
   },
 };
 
-class BrowserDocshellFollower {
-  /**
-   * Follows the <browser> belonging to the `xulBrowser`'s current docshell.
-   *
-   * @param {XULElement} xulBrowser A <browser> tag.
-   * @param {function} onBrowserChange Called when the <browser> changes.
-   */
-  constructor(xulBrowser, onBrowserChange) {
-    this.xulBrowser = xulBrowser;
-    this.onBrowserChange = onBrowserChange;
-
-    xulBrowser.addEventListener("SwapDocShells", this);
-  }
-
-  destroy() {
-    this.xulBrowser.removeEventListener("SwapDocShells", this);
-    this.xulBrowser = null;
-  }
-
-  handleEvent({detail: otherBrowser}) {
-    this.xulBrowser.removeEventListener("SwapDocShells", this);
-    this.xulBrowser = otherBrowser;
-    this.xulBrowser.addEventListener("SwapDocShells", this);
-    this.onBrowserChange(otherBrowser);
-  }
-}
-
 /**
  * The proxied parent side of a context in ExtensionChild.jsm, for the
  * parent side of a proxied API.
  */
 class ProxyContextParent extends BaseContext {
   constructor(envType, extension, params, xulBrowser, principal) {
     super(envType, extension);
 
     this.uri = NetUtil.newURI(params.url);
 
     this.incognito = params.incognito;
 
     // This message manager is used by ParentAPIManager to send messages and to
     // close the ProxyContext if the underlying message manager closes. This
     // message manager object may change when `xulBrowser` swaps docshells, e.g.
     // when a tab is moved to a different window.
-    this.currentMessageManager = xulBrowser.messageManager;
-    this._docShellTracker = new BrowserDocshellFollower(
-      xulBrowser, this.onBrowserChange.bind(this));
+    this.messageManagerProxy = new MessageManagerProxy(xulBrowser);
 
     Object.defineProperty(this, "principal", {
       value: principal, enumerable: true, configurable: true,
     });
 
     // TODO: Replace this with a Sandbox with our content principal when
     // we move to separate processes.
     if (params.cloneScope) {
@@ -297,36 +269,29 @@ class ProxyContextParent extends BaseCon
 
     apiManager.emit("proxy-context-load", this);
   }
 
   get cloneScope() {
     return this.sandbox;
   }
 
-  onBrowserChange(browser) {
-    // Make sure that the message manager is set. Otherwise the ProxyContext may
-    // never be destroyed because the ParentAPIManager would fail to detect that
-    // the message manager is closed.
-    if (!browser.messageManager) {
-      throw new Error("BrowserDocshellFollower: The new browser has no message manager");
-    }
-
-    this.currentMessageManager = browser.messageManager;
+  get parentMessageManager() {
+    return this.messageManagerProxy.messageManager;
   }
 
   shutdown() {
     this.unload();
   }
 
   unload() {
     if (this.unloaded) {
       return;
     }
-    this._docShellTracker.destroy();
+    this.messageManagerProxy.dispose();
     super.unload();
     apiManager.emit("proxy-context-unload", this);
   }
 }
 
 defineLazyGetter(ProxyContextParent.prototype, "apiObj", function() {
   let obj = {};
   GlobalManager.injectInObject(this, false, obj);
@@ -404,17 +369,17 @@ ParentAPIManager = {
     Services.mm.addMessageListener("API:AddListener", this);
     Services.mm.addMessageListener("API:RemoveListener", this);
   },
 
   observe(subject, topic, data) {
     if (topic === "message-manager-close") {
       let mm = subject;
       for (let [childId, context] of this.proxyContexts) {
-        if (context.currentMessageManager === mm) {
+        if (context.parentMessageManager === mm) {
           this.closeProxyContext(childId);
         }
       }
     }
   },
 
   shutdownExtension(extensionId) {
     for (let [childId, context] of this.proxyContexts) {
@@ -482,66 +447,66 @@ ParentAPIManager = {
     if (context) {
       context.unload();
       this.proxyContexts.delete(childId);
     }
   },
 
   call(data, target) {
     let context = this.getContextById(data.childId);
-    if (context.currentMessageManager !== target.messageManager) {
+    if (context.parentMessageManager !== target.messageManager) {
       Cu.reportError("WebExtension warning: Message manager unexpectedly changed");
     }
 
     try {
       let args = Cu.cloneInto(data.args, context.sandbox);
       let result = findPathInObject(context.apiObj, data.path)(...args);
 
       if (data.callId) {
         result = result || Promise.resolve();
 
         result.then(result => {
           result = result instanceof SpreadArgs ? [...result] : [result];
 
-          context.currentMessageManager.sendAsyncMessage("API:CallResult", {
+          context.parentMessageManager.sendAsyncMessage("API:CallResult", {
             childId: data.childId,
             callId: data.callId,
             result,
           });
         }, error => {
           error = context.normalizeError(error);
-          context.currentMessageManager.sendAsyncMessage("API:CallResult", {
+          context.parentMessageManager.sendAsyncMessage("API:CallResult", {
             childId: data.childId,
             callId: data.callId,
             error: {message: error.message},
           });
         });
       }
     } catch (e) {
       if (data.callId) {
         let error = context.normalizeError(e);
-        context.currentMessageManager.sendAsyncMessage("API:CallResult", {
+        context.parentMessageManager.sendAsyncMessage("API:CallResult", {
           childId: data.childId,
           callId: data.callId,
           error: {message: error.message},
         });
       } else {
         Cu.reportError(e);
       }
     }
   },
 
   addListener(data, target) {
     let context = this.getContextById(data.childId);
-    if (context.currentMessageManager !== target.messageManager) {
+    if (context.parentMessageManager !== target.messageManager) {
       Cu.reportError("WebExtension warning: Message manager unexpectedly changed");
     }
 
     function listener(...listenerArgs) {
-      context.currentMessageManager.sendAsyncMessage("API:RunListener", {
+      context.parentMessageManager.sendAsyncMessage("API:RunListener", {
         childId: data.childId,
         path: data.path,
         args: listenerArgs,
       });
     }
 
     context.listenerProxies.set(data.path, listener);