gecko-dev/testing/marionette/marionette-frame-manager.js
Ryan VanderMeulen 4355764776 Backed out 16 changesets (bug 1107706) for Gaia JS integration test failures.
Backed out changeset d026794b4c0b (bug 1107706)
Backed out changeset bb481b2d170a (bug 1107706)
Backed out changeset 71eba829a8b4 (bug 1107706)
Backed out changeset 3ca5a996676e (bug 1107706)
Backed out changeset 18c48c6a0cd5 (bug 1107706)
Backed out changeset 5dce917aeb92 (bug 1107706)
Backed out changeset 933d7aa1c709 (bug 1107706)
Backed out changeset 0c6e1484ae7a (bug 1107706)
Backed out changeset 9972f443d70e (bug 1107706)
Backed out changeset 20f9b7b24fc5 (bug 1107706)
Backed out changeset 1f4ba5b0fc4f (bug 1107706)
Backed out changeset a4a8e755d815 (bug 1107706)
Backed out changeset 593a7917f917 (bug 1107706)
Backed out changeset 502320aec21f (bug 1107706)
Backed out changeset 60b58aed6d27 (bug 1107706)
Backed out changeset c8315bbbc104 (bug 1107706)

CLOSED TREE

--HG--
rename : testing/marionette/actions.js => testing/marionette/marionette-actions.js
rename : testing/marionette/common.js => testing/marionette/marionette-common.js
rename : testing/marionette/elements.js => testing/marionette/marionette-elements.js
rename : testing/marionette/frame-manager.js => testing/marionette/marionette-frame-manager.js
rename : testing/marionette/listener.js => testing/marionette/marionette-listener.js
rename : testing/marionette/sendkeys.js => testing/marionette/marionette-sendkeys.js
rename : testing/marionette/simpletest.js => testing/marionette/marionette-simpletest.js
2015-03-24 13:54:55 -04:00

248 lines
12 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
this.EXPORTED_SYMBOLS = [
"FrameManager"
];
let FRAME_SCRIPT = "chrome://marionette/content/marionette-listener.js";
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Log.jsm");
let logger = Log.repository.getLogger("Marionette");
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader);
let specialpowers = {};
//list of OOP frames that has the frame script loaded
let remoteFrames = [];
/**
* An object representing a frame that Marionette has loaded a
* frame script in.
*/
function MarionetteRemoteFrame(windowId, frameId) {
this.windowId = windowId; //outerWindowId relative to main process
this.frameId = frameId; //actual frame relative to windowId's frames list
this.targetFrameId = this.frameId; //assigned FrameId, used for messaging
};
/**
* The FrameManager will maintain the list of Out Of Process (OOP) frames and will handle
* frame switching between them.
* It handles explicit frame switching (switchToFrame), and implicit frame switching, which
* occurs when a modal dialog is triggered in B2G.
*
*/
this.FrameManager = function FrameManager(server) {
//messageManager maintains the messageManager for the current process' chrome frame or the global message manager
this.currentRemoteFrame = null; //holds a member of remoteFrames (for an OOP frame) or null (for the main process)
this.previousRemoteFrame = null; //frame we'll need to restore once interrupt is gone
this.handledModal = false; //set to true when we have been interrupted by a modal
this.server = server; // a reference to the marionette server
};
FrameManager.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener,
Ci.nsISupportsWeakReference]),
/**
* Receives all messages from content messageManager
*/
receiveMessage: function FM_receiveMessage(message) {
switch (message.name) {
case "MarionetteFrame:getInterruptedState":
// This will return true if the calling frame was interrupted by a modal dialog
if (this.previousRemoteFrame) {
let interruptedFrame = Services.wm.getOuterWindowWithId(this.previousRemoteFrame.windowId);//get the frame window of the interrupted frame
if (this.previousRemoteFrame.frameId != null) {
interruptedFrame = interruptedFrame.document.getElementsByTagName("iframe")[this.previousRemoteFrame.frameId]; //find the OOP frame
}
//check if the interrupted frame is the same as the calling frame
if (interruptedFrame.src == message.target.src) {
return {value: this.handledModal};
}
}
else if (this.currentRemoteFrame == null) {
// we get here if previousRemoteFrame and currentRemoteFrame are null, ie: if we're in a non-OOP process, or we haven't switched into an OOP frame, in which case, handledModal can't be set to true.
return {value: this.handledModal};
}
return {value: false};
case "MarionetteFrame:handleModal":
/*
* handleModal is called when we need to switch frames to the main process due to a modal dialog interrupt.
*/
// If previousRemoteFrame was set, that means we switched into a remote frame.
// If this is the case, then we want to switch back into the system frame.
// If it isn't the case, then we're in a non-OOP environment, so we don't need to handle remote frames
let isLocal = true;
if (this.currentRemoteFrame != null) {
isLocal = false;
this.removeMessageManagerListeners(this.currentRemoteFrame.messageManager.get());
//store the previous frame so we can switch back to it when the modal is dismissed
this.previousRemoteFrame = this.currentRemoteFrame;
//by setting currentRemoteFrame to null, it signifies we're in the main process
this.currentRemoteFrame = null;
this.server.messageManager = Cc["@mozilla.org/globalmessagemanager;1"]
.getService(Ci.nsIMessageBroadcaster);
}
this.handledModal = true;
this.server.sendOk(this.server.command_id);
return {value: isLocal};
case "MarionetteFrame:getCurrentFrameId":
if (this.currentRemoteFrame != null) {
return this.currentRemoteFrame.frameId;
}
}
},
//This is just 'switch to OOP frame'. We're handling this here so we can maintain a list of remoteFrames.
switchToFrame: function FM_switchToFrame(message) {
// Switch to a remote frame.
let frameWindow = Services.wm.getOuterWindowWithId(message.json.win); //get the original frame window
let oopFrame = frameWindow.document.getElementsByTagName("iframe")[message.json.frame]; //find the OOP frame
let mm = oopFrame.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager; //get the OOP frame's mm
if (!specialpowers.hasOwnProperty("specialPowersObserver")) {
loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserver.js",
specialpowers);
}
// See if this frame already has our frame script loaded in it; if so,
// just wake it up.
for (let i = 0; i < remoteFrames.length; i++) {
let frame = remoteFrames[i];
let frameMessageManager = frame.messageManager.get();
logger.info("trying remote frame " + i);
try {
frameMessageManager.sendAsyncMessage("aliveCheck", {});
}
catch(e) {
if (e.result == Components.results.NS_ERROR_NOT_INITIALIZED) {
logger.info("deleting frame");
remoteFrames.splice(i, 1);
continue;
}
}
if (frameMessageManager == mm) {
this.currentRemoteFrame = frame;
this.addMessageManagerListeners(mm);
if (!frame.specialPowersObserver) {
frame.specialPowersObserver = new specialpowers.SpecialPowersObserver();
frame.specialPowersObserver.init(mm);
}
mm.sendAsyncMessage("Marionette:restart", {});
return oopFrame.id;
}
}
// If we get here, then we need to load the frame script in this frame,
// and set the frame's ChromeMessageSender as the active message manager the server will listen to
this.addMessageManagerListeners(mm);
let aFrame = new MarionetteRemoteFrame(message.json.win, message.json.frame);
aFrame.messageManager = Cu.getWeakReference(mm);
remoteFrames.push(aFrame);
this.currentRemoteFrame = aFrame;
logger.info("frame-manager load script: " + mm.toString());
mm.loadFrameScript(FRAME_SCRIPT, true, true);
aFrame.specialPowersObserver = new specialpowers.SpecialPowersObserver();
aFrame.specialPowersObserver.init(mm);
return oopFrame.id;
},
/*
* This function handles switching back to the frame that was interrupted by the modal dialog.
* This function gets called by the interrupted frame once the dialog is dismissed and the frame resumes its process
*/
switchToModalOrigin: function FM_switchToModalOrigin() {
//only handle this if we indeed switched out of the modal's originating frame
if (this.previousRemoteFrame != null) {
this.currentRemoteFrame = this.previousRemoteFrame;
this.addMessageManagerListeners(this.currentRemoteFrame.messageManager.get());
}
this.handledModal = false;
},
/**
* This function removes any SpecialPowersObservers from OOP frames.
*/
removeSpecialPowers: function FM_removeSpecialPowers() {
for (let i = 0; i < remoteFrames.length; i++) {
let frame = remoteFrames[i];
if (frame.specialPowersObserver) {
frame.specialPowersObserver.uninit();
frame.specialPowersObserver = null;
}
}
},
/**
* Adds message listeners to the server, listening for messages from content frame scripts.
* It also adds a "MarionetteFrame:getInterruptedState" message listener to the FrameManager,
* so the frame manager's state can be checked by the frame
*
* @param object messageManager
* The messageManager object (ChromeMessageBroadcaster or ChromeMessageSender)
* to which the listeners should be added.
*/
addMessageManagerListeners: function MDA_addMessageManagerListeners(messageManager) {
messageManager.addWeakMessageListener("Marionette:ok", this.server);
messageManager.addWeakMessageListener("Marionette:done", this.server);
messageManager.addWeakMessageListener("Marionette:error", this.server);
messageManager.addWeakMessageListener("Marionette:emitTouchEvent", this.server);
messageManager.addWeakMessageListener("Marionette:log", this.server);
messageManager.addWeakMessageListener("Marionette:register", this.server);
messageManager.addWeakMessageListener("Marionette:runEmulatorCmd", this.server);
messageManager.addWeakMessageListener("Marionette:runEmulatorShell", this.server);
messageManager.addWeakMessageListener("Marionette:shareData", this.server);
messageManager.addWeakMessageListener("Marionette:switchToModalOrigin", this.server);
messageManager.addWeakMessageListener("Marionette:switchToFrame", this.server);
messageManager.addWeakMessageListener("Marionette:switchedToFrame", this.server);
messageManager.addWeakMessageListener("Marionette:addCookie", this.server);
messageManager.addWeakMessageListener("Marionette:getVisibleCookies", this.server);
messageManager.addWeakMessageListener("Marionette:deleteCookie", this.server);
messageManager.addWeakMessageListener("Marionette:listenersAttached", this.server);
messageManager.addWeakMessageListener("MarionetteFrame:handleModal", this);
messageManager.addWeakMessageListener("MarionetteFrame:getCurrentFrameId", this);
messageManager.addWeakMessageListener("MarionetteFrame:getInterruptedState", this);
},
/**
* Removes listeners for messages from content frame scripts.
* We do not remove the "MarionetteFrame:getInterruptedState" or the
* "Marioentte:switchToModalOrigin" message listener,
* because we want to allow all known frames to contact the frame manager so that
* it can check if it was interrupted, and if so, it will call switchToModalOrigin
* when its process gets resumed.
*
* @param object messageManager
* The messageManager object (ChromeMessageBroadcaster or ChromeMessageSender)
* from which the listeners should be removed.
*/
removeMessageManagerListeners: function MDA_removeMessageManagerListeners(messageManager) {
messageManager.removeWeakMessageListener("Marionette:ok", this.server);
messageManager.removeWeakMessageListener("Marionette:done", this.server);
messageManager.removeWeakMessageListener("Marionette:error", this.server);
messageManager.removeWeakMessageListener("Marionette:log", this.server);
messageManager.removeWeakMessageListener("Marionette:shareData", this.server);
messageManager.removeWeakMessageListener("Marionette:register", this.server);
messageManager.removeWeakMessageListener("Marionette:runEmulatorCmd", this.server);
messageManager.removeWeakMessageListener("Marionette:runEmulatorShell", this.server);
messageManager.removeWeakMessageListener("Marionette:switchToFrame", this.server);
messageManager.removeWeakMessageListener("Marionette:switchedToFrame", this.server);
messageManager.removeWeakMessageListener("Marionette:addCookie", this.server);
messageManager.removeWeakMessageListener("Marionette:getVisibleCookies", this.server);
messageManager.removeWeakMessageListener("Marionette:deleteCookie", this.server);
messageManager.removeWeakMessageListener("Marionette:listenersAttached", this.server);
messageManager.removeWeakMessageListener("MarionetteFrame:handleModal", this);
messageManager.removeWeakMessageListener("MarionetteFrame:getCurrentFrameId", this);
},
};