Bug 1445537: Track frameloader swaps when monitoring for channel disconnections. r?aswan draft
authorKris Maglione <maglione.k@gmail.com>
Wed, 14 Mar 2018 15:44:08 -0700
changeset 767681 8a711859f84977edec64f3fc3b9aca21577a80fc
parent 767669 18b2f984204f3582f7dcde76b11799aa49309cf6
push id102667
push usermaglione.k@gmail.com
push dateWed, 14 Mar 2018 22:44:37 +0000
reviewersaswan
bugs1445537
milestone61.0a1
Bug 1445537: Track frameloader swaps when monitoring for channel disconnections. r?aswan When we swap <browser> frameloaders, the message managers on the parent side also change. And since a frameloader swap is usually followed by the original <browser> and its message manager being destroyed, this leads us to think the message manager has disconneced earlier than it actually does. MozReview-Commit-ID: LC9aaoynWzH
toolkit/components/extensions/ExtensionParent.jsm
--- a/toolkit/components/extensions/ExtensionParent.jsm
+++ b/toolkit/components/extensions/ExtensionParent.jsm
@@ -198,39 +198,49 @@ ProxyMessenger = {
     // reason for having a parent process manager here.
     let messageManagers = [Services.mm, Services.ppmm];
 
     MessageChannel.addListener(messageManagers, "Extension:Connect", this);
     MessageChannel.addListener(messageManagers, "Extension:Message", this);
     MessageChannel.addListener(messageManagers, "Extension:Port:Disconnect", this);
     MessageChannel.addListener(messageManagers, "Extension:Port:PostMessage", this);
 
-    Services.obs.addObserver(this, "message-manager-close");
+    Services.obs.addObserver(this, "message-manager-disconnect");
 
     this.ports = new DefaultMap(() => new Map());
   },
 
   observe(subject, topic, data) {
-    if (topic === "message-manager-close") {
+    if (topic === "message-manager-disconnect") {
       if (this.ports.has(subject)) {
         let ports = this.ports.get(subject);
         this.ports.delete(subject);
 
         for (let [portId, {sender, recipient, receiverMM}] of ports.entries()) {
           recipient.portId = portId;
           MessageChannel.sendMessage(receiverMM, "Extension:Port:Disconnect", null, {
             sender,
             recipient,
             responseType: MessageChannel.RESPONSE_TYPE_NONE,
           }).catch(() => {});
         }
       }
     }
   },
 
+  handleEvent(event) {
+    if (event.type === "SwapDocShells") {
+      let {messageManager} = event.originalTarget;
+      if (this.ports.has(messageManager)) {
+        this.ports.set(event.detail.messageManager, this.ports.get(messageManager));
+        this.ports.delete(messageManager);
+      }
+    }
+  },
+
   async receiveMessage({target, messageName, channelId, sender, recipient, data, responseType}) {
     if (recipient.toNativeApp) {
       let {childId, toNativeApp} = recipient;
       if (messageName == "Extension:Message") {
         let context = ParentAPIManager.getContextById(childId);
         return new NativeApp(context, toNativeApp).sendMessage(data);
       }
       if (messageName == "Extension:Connect") {
@@ -263,22 +273,26 @@ ProxyMessenger = {
 
     let promise1 = MessageChannel.sendMessage(receiverMM, messageName, data, {
       sender,
       recipient,
       responseType,
     });
 
     if (messageName === "Extension:Connect") {
+      target.addEventListener("SwapDocShells", this, {once: true});
+
       this.ports.get(target.messageManager).set(data.portId, {receiverMM, sender, recipient});
       promise1.catch(() => {
         this.ports.get(target.messageManager).delete(data.portId);
       });
     } else if (messageName === "Extension:Port:Disconnect") {
-      this.ports.get(target.messageManager).delete(data.portId);
+      if (target.messageManager) {
+        this.ports.get(target.messageManager).delete(data.portId);
+      }
     }
 
 
     if (!(extension.isEmbedded || recipient.toProxyScript) || !extension.remote) {
       return promise1;
     }
 
     // If we have a proxy script sandbox or a remote, embedded extension, where