bug 1523104: remote: wait for browser element init before creating Target; r=ato
authorAlexandre Poirot <poirot.alex@gmail.com>
Thu, 14 Feb 2019 01:20:55 -0800
changeset 521084 16812017daad
parent 521083 ff4ff4765f3b
child 521085 4abd3301e839
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersato
bugs1523104
milestone67.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 1523104: remote: wait for browser element init before creating Target; r=ato
remote/RemoteAgent.js
remote/WindowManager.jsm
remote/test/browser/browser.ini
--- a/remote/RemoteAgent.js
+++ b/remote/RemoteAgent.js
@@ -184,43 +184,54 @@ class ParentRemoteAgent {
 }
 
 class Targets {
   constructor() {
     // browser context ID -> Target<XULElement>
     this._targets = new Map();
   }
 
-  /** @param {XULElement|Target} subject */
-  connect(subject) {
-    let target = subject;
-    if (!(subject instanceof Target)) {
-      target = new Target(subject);
+  /** @param BrowserElement browser */
+  async connect(browser) {
+    // The tab may just have been created and not fully initialized yet.
+    // Target class expects BrowserElement.browsingContext to be defined
+    // whereas it is asynchronously set by the custom element class.
+    // At least ensure that this property is set before instantiating the target.
+    if (!browser.browsingContext) {
+      await new Promise(resolve => {
+        const onInit = () => {
+          browser.messageManager.removeMessageListener("Browser:Init", onInit);
+          resolve();
+        };
+        browser.messageManager.addMessageListener("Browser:Init", onInit);
+      });
     }
+    const target = new Target(browser);
 
     target.connect();
     this._targets.set(target.id, target);
   }
 
-  /** @param {XULElement|Target} subject */
-  disconnect(subject) {
-    let target = subject;
-    if (!(subject instanceof Target)) {
-      target = this._targets.get(subject.browsingContext.id);
+  /** @param BrowserElement browser */
+  disconnect(browser) {
+    // Ignore the browsers that haven't had time to initialize.
+    if (!browser.browsingContext) {
+      return;
     }
+    let target = this._targets.get(browser.browsingContext.id);
 
     if (target) {
       target.disconnect();
       this._targets.delete(target.id);
     }
   }
 
   clear() {
     for (const target of this) {
-      this.disconnect(target);
+      this.disconnect(target.browser);
     }
   }
 
   get size() {
     return this._targets.size;
   }
 
   * [Symbol.iterator]() {
--- a/remote/WindowManager.jsm
+++ b/remote/WindowManager.jsm
@@ -130,16 +130,21 @@ class TabObserver {
   // WindowObserver
 
   async onWindowOpen(window) {
     if (!window.gBrowser) {
       return;
     }
 
     for (const tab of window.gBrowser.tabs) {
+      // If `linkedBrowser` isn't set, it means that the tab is still initializing
+      // and a `TabOpen` event will be fired once it is all set.
+      if (!tab.linkedBrowser) {
+        continue;
+      }
       this.onTabOpen(tab);
     }
 
     window.addEventListener("TabOpen", ({target}) => this.onTabOpen(target));
     window.addEventListener("TabClose", ({target}) => this.onTabClose(target));
   }
 
   onWindowClose(window) {
--- a/remote/test/browser/browser.ini
+++ b/remote/test/browser/browser.ini
@@ -1,8 +1,9 @@
 [DEFAULT]
 tags = remote
 subsuite = remote
 support-files =
   chrome-remote-interface.js
   head.js
 
 [browser_cdp.js]
+[browser_tabs.js]