Bug 1426154 - Use targetted IPC messages to talk to content frames. r?automatedtester draft
authorAndreas Tolfsen <ato@sny.no>
Tue, 09 Jan 2018 17:48:57 +0000
changeset 718616 badfa8828b930fd6e6923198d1e7e60483b2b0b3
parent 718598 2438a090b77a56b38547f7250bb499cb2e1ffcce
child 718617 99a4b5f093bc187faa909da615c00c3d197e2516
push id95004
push userbmo:ato@sny.no
push dateWed, 10 Jan 2018 18:01:43 +0000
reviewersautomatedtester
bugs1426154
milestone59.0a1
Bug 1426154 - Use targetted IPC messages to talk to content frames. r?automatedtester Prior to this patch Marionette used a broadcasting technique that sent every IPC message to every registered content frame's message manager. This was implemented in GeckoDriver#sendAsync and worked by appending the frame's outerWindowID to the message name to ensure it reached the correct recipient. Because it is hugely wasteful for every content frame to receive every IPC message, this patch changes it so that we use a frame's dedicated message manager to only channel messages it cares about. A content frame's direct message manager is stored in browser.Context#messageManager, whereas GeckoDriver#mm is always the global message manager. MozReview-Commit-ID: L0sD3VhzStv
testing/marionette/driver.js
testing/marionette/listener.js
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -333,18 +333,18 @@ GeckoDriver.prototype.sendAsync = functi
   // is used for all chrome <-> content communication
   // this can be removed.
   if (commandID) {
     payload.commandID = commandID;
   }
 
   this.curBrowser.executeWhenReady(() => {
     if (this.curBrowser.curFrameId) {
-      let target = `Marionette:${name}${this.curBrowser.curFrameId}`;
-      this.mm.broadcastAsyncMessage(target, payload);
+      let target = `Marionette:${name}`;
+      this.curBrowser.messageManager.sendAsyncMessage(target, payload);
     } else {
       throw new NoSuchWindowError(
           "No such content frame; perhaps the listener was not registered?");
     }
   });
 };
 
 /**
@@ -1051,19 +1051,18 @@ GeckoDriver.prototype.get = async functi
   // readyState and send errors.
   this.curBrowser.pendingCommands.push(() => {
     let parameters = {
       // TODO(ato): Bug 1242595
       commandID: this.listener.activeMessageId,
       pageTimeout: this.timeouts.pageLoad,
       startTime: new Date().getTime(),
     };
-    this.mm.broadcastAsyncMessage(
-        "Marionette:waitForPageLoaded" + this.curBrowser.curFrameId,
-        parameters);
+    this.curBrowser.messageManager.sendAsyncMessage(
+        "Marionette:waitForPageLoaded", parameters);
   });
 
   await get;
 
   this.curBrowser.contentBrowser.focus();
 };
 
 /**
@@ -1171,19 +1170,18 @@ GeckoDriver.prototype.goBack = async fun
   this.curBrowser.pendingCommands.push(() => {
     let parameters = {
       // TODO(ato): Bug 1242595
       commandID: this.listener.activeMessageId,
       lastSeenURL: lastURL.toString(),
       pageTimeout: this.timeouts.pageLoad,
       startTime: new Date().getTime(),
     };
-    this.mm.broadcastAsyncMessage(
-        "Marionette:waitForPageLoaded" + this.curBrowser.curFrameId,
-        parameters);
+    this.curBrowser.messageManager.sendAsyncMessage(
+        "Marionette:waitForPageLoaded", parameters);
   });
 
   await goBack;
 };
 
 /**
  * Cause the browser to traverse one step forward in the joint history
  * of the current browsing context.
@@ -1215,19 +1213,18 @@ GeckoDriver.prototype.goForward = async 
   this.curBrowser.pendingCommands.push(() => {
     let parameters = {
       // TODO(ato): Bug 1242595
       commandID: this.listener.activeMessageId,
       lastSeenURL: lastURL.toString(),
       pageTimeout: this.timeouts.pageLoad,
       startTime: new Date().getTime(),
     };
-    this.mm.broadcastAsyncMessage(
-        "Marionette:waitForPageLoaded" + this.curBrowser.curFrameId,
-        parameters);
+    this.curBrowser.messageManager.sendAsyncMessage(
+        "Marionette:waitForPageLoaded", parameters);
   });
 
   await goForward;
 };
 
 /**
  * Causes the browser to reload the page in current top-level browsing
  * context.
@@ -1252,19 +1249,18 @@ GeckoDriver.prototype.refresh = async fu
   // readyState and send errors.
   this.curBrowser.pendingCommands.push(() => {
     let parameters = {
       // TODO(ato): Bug 1242595
       commandID: this.listener.activeMessageId,
       pageTimeout: this.timeouts.pageLoad,
       startTime: new Date().getTime(),
     };
-    this.mm.broadcastAsyncMessage(
-        "Marionette:waitForPageLoaded" + this.curBrowser.curFrameId,
-        parameters);
+    this.curBrowser.messageManager.sendAsyncMessage(
+        "Marionette:waitForPageLoaded", parameters);
   });
 
   await refresh;
 };
 
 /**
  * Forces an update for the given browser's id.
  */
@@ -2130,19 +2126,18 @@ GeckoDriver.prototype.clickElement = asy
       // readyState and send errors.
       this.curBrowser.pendingCommands.push(() => {
         let parameters = {
           // TODO(ato): Bug 1242595
           commandID: this.listener.activeMessageId,
           pageTimeout: this.timeouts.pageLoad,
           startTime: new Date().getTime(),
         };
-        this.mm.broadcastAsyncMessage(
-            `Marionette:waitForPageLoaded${this.curBrowser.curFrameId}`,
-            parameters);
+        this.curBrowser.messageManager.sendAsyncMessage(
+            "Marionette:waitForPageLoaded", parameters);
       });
 
       await click;
       break;
   }
 };
 
 /**
@@ -2777,20 +2772,19 @@ GeckoDriver.prototype.closeChromeWindow 
 GeckoDriver.prototype.deleteSession = function() {
   if (this.curBrowser !== null) {
     // frame scripts can be safely reused
     Preferences.set(CONTENT_LISTENER_PREF, false);
 
     // delete session in each frame in each browser
     for (let win in this.browsers) {
       let browser = this.browsers[win];
-      for (let i in browser.knownFrames) {
-        globalMessageManager.broadcastAsyncMessage(
-            "Marionette:deleteSession" + browser.knownFrames[i], {});
-      }
+      browser.knownFrames.forEach(() => {
+        globalMessageManager.broadcastAsyncMessage("Marionette:deleteSession");
+      });
     }
 
     for (let win of this.windows) {
       if (win.messageManager) {
         win.messageManager.removeDelayedFrameScript(FRAME_SCRIPT);
       } else {
         logger.error(
             `Could not remove listener from page ${win.location.href}`);
--- a/testing/marionette/listener.js
+++ b/testing/marionette/listener.js
@@ -487,24 +487,16 @@ function dispatch(fn) {
       resolve(rv);
     });
 
     req.then(rv => sendResponse(rv, id), err => sendError(err, id))
         .catch(err => sendError(err, id));
   };
 }
 
-function addMessageListenerId(messageName, handler) {
-  addMessageListener(messageName + outerWindowID, handler);
-}
-
-function removeMessageListenerId(messageName, handler) {
-  removeMessageListener(messageName + outerWindowID, handler);
-}
-
 let getPageSourceFn = dispatch(getPageSource);
 let getActiveElementFn = dispatch(getActiveElement);
 let getElementAttributeFn = dispatch(getElementAttribute);
 let getElementPropertyFn = dispatch(getElementProperty);
 let getElementTextFn = dispatch(getElementText);
 let getElementTagNameFn = dispatch(getElementTagName);
 let getElementRectFn = dispatch(getElementRect);
 let isElementEnabledFn = dispatch(isElementEnabled);
@@ -525,56 +517,56 @@ let executeFn = dispatch(execute);
 let executeInSandboxFn = dispatch(executeInSandbox);
 let sendKeysToElementFn = dispatch(sendKeysToElement);
 let reftestWaitFn = dispatch(reftestWait);
 
 /**
  * Start all message listeners
  */
 function startListeners() {
-  addMessageListenerId("Marionette:newSession", newSession);
-  addMessageListenerId("Marionette:execute", executeFn);
-  addMessageListenerId("Marionette:executeInSandbox", executeInSandboxFn);
-  addMessageListenerId("Marionette:singleTap", singleTapFn);
-  addMessageListenerId("Marionette:performActions", performActionsFn);
-  addMessageListenerId("Marionette:releaseActions", releaseActionsFn);
-  addMessageListenerId("Marionette:actionChain", actionChainFn);
-  addMessageListenerId("Marionette:multiAction", multiActionFn);
-  addMessageListenerId("Marionette:get", get);
-  addMessageListenerId("Marionette:waitForPageLoaded", waitForPageLoaded);
-  addMessageListenerId("Marionette:cancelRequest", cancelRequest);
-  addMessageListenerId("Marionette:getPageSource", getPageSourceFn);
-  addMessageListenerId("Marionette:goBack", goBack);
-  addMessageListenerId("Marionette:goForward", goForward);
-  addMessageListenerId("Marionette:refresh", refresh);
-  addMessageListenerId("Marionette:findElementContent", findElementContentFn);
-  addMessageListenerId(
+  addMessageListener("Marionette:newSession", newSession);
+  addMessageListener("Marionette:execute", executeFn);
+  addMessageListener("Marionette:executeInSandbox", executeInSandboxFn);
+  addMessageListener("Marionette:singleTap", singleTapFn);
+  addMessageListener("Marionette:performActions", performActionsFn);
+  addMessageListener("Marionette:releaseActions", releaseActionsFn);
+  addMessageListener("Marionette:actionChain", actionChainFn);
+  addMessageListener("Marionette:multiAction", multiActionFn);
+  addMessageListener("Marionette:get", get);
+  addMessageListener("Marionette:waitForPageLoaded", waitForPageLoaded);
+  addMessageListener("Marionette:cancelRequest", cancelRequest);
+  addMessageListener("Marionette:getPageSource", getPageSourceFn);
+  addMessageListener("Marionette:goBack", goBack);
+  addMessageListener("Marionette:goForward", goForward);
+  addMessageListener("Marionette:refresh", refresh);
+  addMessageListener("Marionette:findElementContent", findElementContentFn);
+  addMessageListener(
       "Marionette:findElementsContent", findElementsContentFn);
-  addMessageListenerId("Marionette:getActiveElement", getActiveElementFn);
-  addMessageListenerId("Marionette:clickElement", clickElement);
-  addMessageListenerId(
+  addMessageListener("Marionette:getActiveElement", getActiveElementFn);
+  addMessageListener("Marionette:clickElement", clickElement);
+  addMessageListener(
       "Marionette:getElementAttribute", getElementAttributeFn);
-  addMessageListenerId("Marionette:getElementProperty", getElementPropertyFn);
-  addMessageListenerId("Marionette:getElementText", getElementTextFn);
-  addMessageListenerId("Marionette:getElementTagName", getElementTagNameFn);
-  addMessageListenerId("Marionette:isElementDisplayed", isElementDisplayedFn);
-  addMessageListenerId(
+  addMessageListener("Marionette:getElementProperty", getElementPropertyFn);
+  addMessageListener("Marionette:getElementText", getElementTextFn);
+  addMessageListener("Marionette:getElementTagName", getElementTagNameFn);
+  addMessageListener("Marionette:isElementDisplayed", isElementDisplayedFn);
+  addMessageListener(
       "Marionette:getElementValueOfCssProperty",
       getElementValueOfCssPropertyFn);
-  addMessageListenerId("Marionette:getElementRect", getElementRectFn);
-  addMessageListenerId("Marionette:isElementEnabled", isElementEnabledFn);
-  addMessageListenerId("Marionette:isElementSelected", isElementSelectedFn);
-  addMessageListenerId("Marionette:sendKeysToElement", sendKeysToElementFn);
-  addMessageListenerId("Marionette:clearElement", clearElementFn);
-  addMessageListenerId("Marionette:switchToFrame", switchToFrame);
-  addMessageListenerId("Marionette:switchToParentFrame", switchToParentFrame);
-  addMessageListenerId("Marionette:switchToShadowRoot", switchToShadowRootFn);
-  addMessageListenerId("Marionette:deleteSession", deleteSession);
-  addMessageListenerId("Marionette:takeScreenshot", takeScreenshotFn);
-  addMessageListenerId("Marionette:reftestWait", reftestWaitFn);
+  addMessageListener("Marionette:getElementRect", getElementRectFn);
+  addMessageListener("Marionette:isElementEnabled", isElementEnabledFn);
+  addMessageListener("Marionette:isElementSelected", isElementSelectedFn);
+  addMessageListener("Marionette:sendKeysToElement", sendKeysToElementFn);
+  addMessageListener("Marionette:clearElement", clearElementFn);
+  addMessageListener("Marionette:switchToFrame", switchToFrame);
+  addMessageListener("Marionette:switchToParentFrame", switchToParentFrame);
+  addMessageListener("Marionette:switchToShadowRoot", switchToShadowRootFn);
+  addMessageListener("Marionette:deleteSession", deleteSession);
+  addMessageListener("Marionette:takeScreenshot", takeScreenshotFn);
+  addMessageListener("Marionette:reftestWait", reftestWaitFn);
   addMessageListener("Marionette:DOM:AddEventListener", domAddEventListener);
   addMessageListener("Marionette:DOM:RemoveEventListener", domRemoveEventListener);
 }
 
 /**
  * Called when we start a new session. It registers the
  * current environment, and resets all values
  */
@@ -585,64 +577,64 @@ function newSession() {
   action.inputStateMap = new Map();
   action.inputsToCancel = [];
 }
 
 /**
  * Removes all listeners
  */
 function deleteSession() {
-  removeMessageListenerId("Marionette:newSession", newSession);
-  removeMessageListenerId("Marionette:execute", executeFn);
-  removeMessageListenerId("Marionette:executeInSandbox", executeInSandboxFn);
-  removeMessageListenerId("Marionette:singleTap", singleTapFn);
-  removeMessageListenerId("Marionette:performActions", performActionsFn);
-  removeMessageListenerId("Marionette:releaseActions", releaseActionsFn);
-  removeMessageListenerId("Marionette:actionChain", actionChainFn);
-  removeMessageListenerId("Marionette:multiAction", multiActionFn);
-  removeMessageListenerId("Marionette:get", get);
-  removeMessageListenerId("Marionette:waitForPageLoaded", waitForPageLoaded);
-  removeMessageListenerId("Marionette:cancelRequest", cancelRequest);
-  removeMessageListenerId("Marionette:getPageSource", getPageSourceFn);
-  removeMessageListenerId("Marionette:goBack", goBack);
-  removeMessageListenerId("Marionette:goForward", goForward);
-  removeMessageListenerId("Marionette:refresh", refresh);
-  removeMessageListenerId(
+  removeMessageListener("Marionette:newSession", newSession);
+  removeMessageListener("Marionette:execute", executeFn);
+  removeMessageListener("Marionette:executeInSandbox", executeInSandboxFn);
+  removeMessageListener("Marionette:singleTap", singleTapFn);
+  removeMessageListener("Marionette:performActions", performActionsFn);
+  removeMessageListener("Marionette:releaseActions", releaseActionsFn);
+  removeMessageListener("Marionette:actionChain", actionChainFn);
+  removeMessageListener("Marionette:multiAction", multiActionFn);
+  removeMessageListener("Marionette:get", get);
+  removeMessageListener("Marionette:waitForPageLoaded", waitForPageLoaded);
+  removeMessageListener("Marionette:cancelRequest", cancelRequest);
+  removeMessageListener("Marionette:getPageSource", getPageSourceFn);
+  removeMessageListener("Marionette:goBack", goBack);
+  removeMessageListener("Marionette:goForward", goForward);
+  removeMessageListener("Marionette:refresh", refresh);
+  removeMessageListener(
       "Marionette:findElementContent", findElementContentFn);
-  removeMessageListenerId(
+  removeMessageListener(
       "Marionette:findElementsContent", findElementsContentFn);
-  removeMessageListenerId("Marionette:getActiveElement", getActiveElementFn);
-  removeMessageListenerId("Marionette:clickElement", clickElement);
-  removeMessageListenerId(
+  removeMessageListener("Marionette:getActiveElement", getActiveElementFn);
+  removeMessageListener("Marionette:clickElement", clickElement);
+  removeMessageListener(
       "Marionette:getElementAttribute", getElementAttributeFn);
-  removeMessageListenerId(
+  removeMessageListener(
       "Marionette:getElementProperty", getElementPropertyFn);
-  removeMessageListenerId(
+  removeMessageListener(
       "Marionette:getElementText", getElementTextFn);
-  removeMessageListenerId(
+  removeMessageListener(
       "Marionette:getElementTagName", getElementTagNameFn);
-  removeMessageListenerId(
+  removeMessageListener(
       "Marionette:isElementDisplayed", isElementDisplayedFn);
-  removeMessageListenerId(
+  removeMessageListener(
       "Marionette:getElementValueOfCssProperty",
       getElementValueOfCssPropertyFn);
-  removeMessageListenerId("Marionette:getElementRect", getElementRectFn);
-  removeMessageListenerId("Marionette:isElementEnabled", isElementEnabledFn);
-  removeMessageListenerId(
+  removeMessageListener("Marionette:getElementRect", getElementRectFn);
+  removeMessageListener("Marionette:isElementEnabled", isElementEnabledFn);
+  removeMessageListener(
       "Marionette:isElementSelected", isElementSelectedFn);
-  removeMessageListenerId(
+  removeMessageListener(
       "Marionette:sendKeysToElement", sendKeysToElementFn);
-  removeMessageListenerId("Marionette:clearElement", clearElementFn);
-  removeMessageListenerId("Marionette:switchToFrame", switchToFrame);
-  removeMessageListenerId(
+  removeMessageListener("Marionette:clearElement", clearElementFn);
+  removeMessageListener("Marionette:switchToFrame", switchToFrame);
+  removeMessageListener(
       "Marionette:switchToParentFrame", switchToParentFrame);
-  removeMessageListenerId(
+  removeMessageListener(
       "Marionette:switchToShadowRoot", switchToShadowRootFn);
-  removeMessageListenerId("Marionette:deleteSession", deleteSession);
-  removeMessageListenerId("Marionette:takeScreenshot", takeScreenshotFn);
+  removeMessageListener("Marionette:deleteSession", deleteSession);
+  removeMessageListener("Marionette:takeScreenshot", takeScreenshotFn);
 
   seenEls.clear();
   // reset container frame to the top-most frame
   curContainer = {frame: content, shadowRoot: null};
   curContainer.frame.focus();
   legacyactions.touchIds = {};
   if (action.inputStateMap !== undefined) {
     action.inputStateMap.clear();