Bug 1353559 - Filter out exited browsers from tab list. r=ochameau draft
authorJ. Ryan Stinnett <jryans@gmail.com>
Wed, 05 Apr 2017 07:27:30 -0500
changeset 556134 d13b5a23400546df2983696b5ec47c74294ad53e
parent 555794 3bfed155d5538464ccaa0d6fd4b75e1a616b2265
child 622801 61a202547cd2382ebec79dc6bc0bf256a40f2fde
push id52455
push userbmo:jryans@gmail.com
push dateWed, 05 Apr 2017 12:46:49 +0000
reviewersochameau
bugs1353559
milestone55.0a1
Bug 1353559 - Filter out exited browsers from tab list. r=ochameau This adds higher level protection to ignore exited browser actors, so we don't end up triggering methods like `form` on them, since they won't make much sense anyway. MozReview-Commit-ID: KgUCA04N2fY
devtools/server/actors/root.js
devtools/server/actors/webbrowser.js
--- a/devtools/server/actors/root.js
+++ b/devtools/server/actors/root.js
@@ -270,16 +270,20 @@ RootActor.prototype = {
      * retiring any actors that didn't get listed again, and preparing any
      * new actors to receive packets.
      */
     let newActorPool = new ActorPool(this.conn);
     let tabActorList = [];
     let selected;
     return tabList.getList().then((tabActors) => {
       for (let tabActor of tabActors) {
+        if (tabActor.exited) {
+          // Tab actor may have exited while we were gathering the list.
+          continue;
+        }
         if (tabActor.selected) {
           selected = tabActorList.length;
         }
         tabActor.parentID = this.actorID;
         newActorPool.addActor(tabActor);
         tabActorList.push(tabActor);
       }
       /* DebuggerServer.addGlobalActor support: create actors. */
--- a/devtools/server/actors/webbrowser.js
+++ b/devtools/server/actors/webbrowser.js
@@ -695,29 +695,30 @@ exports.BrowserTabList = BrowserTabList;
  *
  * @param connection The main RDP connection.
  * @param browser <xul:browser> or <iframe mozbrowser> element to connect to.
  */
 function BrowserTabActor(connection, browser) {
   this._conn = connection;
   this._browser = browser;
   this._form = null;
+  this.exited = false;
 }
 
 BrowserTabActor.prototype = {
   connect() {
     let onDestroy = () => {
       if (this._deferredUpdate) {
         // Reject the update promise if the tab was destroyed while requesting an update
         this._deferredUpdate.reject({
           error: "tabDestroyed",
           message: "Tab destroyed while performing a BrowserTabActor update"
         });
       }
-      this._form = null;
+      this.exit();
     };
     let connect = DebuggerServer.connectToChild(this._conn, this._browser, onDestroy);
     return connect.then(form => {
       this._form = form;
       return this;
     });
   },
 
@@ -734,17 +735,17 @@ BrowserTabActor.prototype = {
     return this._browser.messageManager ||
            this._browser.frameLoader.messageManager;
   },
 
   update() {
     // If the child happens to be crashed/close/detach, it won't have _form set,
     // so only request form update if some code is still listening on the other
     // side.
-    if (this._form) {
+    if (!this.exited) {
       this._deferredUpdate = promise.defer();
       let onFormUpdate = msg => {
         // There may be more than just one childtab.js up and running
         if (this._form.actor != msg.json.actor) {
           return;
         }
         this._mm.removeMessageListener("debug:form", onFormUpdate);
         this._form = msg.json;
@@ -808,16 +809,18 @@ BrowserTabActor.prototype = {
     if (!form.url) {
       form.url = this.url;
     }
     return form;
   },
 
   exit() {
     this._browser = null;
+    this._form = null;
+    this.exited = true;
   },
 };
 
 exports.BrowserTabActor = BrowserTabActor;
 
 function BrowserAddonList(connection) {
   this._connection = connection;
   this._actorByAddonId = new Map();