Bug 1445537: Track frameloader swaps when monitoring for channel disconnections. r=aswan
authorKris Maglione <maglione.k@gmail.com>
Wed, 14 Mar 2018 15:44:08 -0700
changeset 408273 6ed4300a066b74d9f7dc2a8c24062f6691c11edb
parent 408272 d36521a0a4ea0f7c0ef554c1acb32c8bc7c642e2
child 408274 c71ee5e970f63c9e433ecad757a1145a78bad3ea
push id33630
push usershindli@mozilla.com
push dateThu, 15 Mar 2018 10:14:59 +0000
treeherdermozilla-central@fcb11e93adf5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaswan
bugs1445537
milestone61.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 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 disconnected 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