mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 14:45:29 +00:00
7fffd2bbd2
--HG-- rename : testing/marionette/marionette-actions.js => testing/marionette/actions.js rename : testing/marionette/marionette-common.js => testing/marionette/common.js rename : testing/marionette/marionette-elements.js => testing/marionette/elements.js rename : testing/marionette/marionette-frame-manager.js => testing/marionette/frame-manager.js rename : testing/marionette/marionette-listener.js => testing/marionette/listener.js rename : testing/marionette/marionette-sendkeys.js => testing/marionette/sendkeys.js rename : testing/marionette/marionette-simpletest.js => testing/marionette/simpletest.js extra : rebase_source : 5eb61551c11d1ff94eb86b18bbd1f98da93d648a extra : source : 91b35cb3308bc80d736e63434f9702e73115c41f
173 lines
5.5 KiB
JavaScript
173 lines
5.5 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/. */
|
|
|
|
"use strict";
|
|
|
|
const {Constructor: CC, classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
|
|
|
const loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader);
|
|
const ServerSocket = CC("@mozilla.org/network/server-socket;1", "nsIServerSocket", "initSpecialConnection");
|
|
|
|
Cu.import("resource://gre/modules/Log.jsm");
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
|
|
Cu.import("chrome://marionette/content/dispatcher.js");
|
|
Cu.import("chrome://marionette/content/driver.js");
|
|
Cu.import("chrome://marionette/content/elements.js");
|
|
Cu.import("chrome://marionette/content/simpletest.js");
|
|
|
|
// Bug 1083711: Load transport.js as an SDK module instead of subscript
|
|
loader.loadSubScript("resource://gre/modules/devtools/transport/transport.js");
|
|
|
|
// Preserve this import order:
|
|
let events = {};
|
|
loader.loadSubScript("chrome://marionette/content/EventUtils.js", events);
|
|
loader.loadSubScript("chrome://marionette/content/ChromeUtils.js", events);
|
|
loader.loadSubScript("chrome://marionette/content/frame-manager.js");
|
|
|
|
const logger = Log.repository.getLogger("Marionette");
|
|
|
|
this.EXPORTED_SYMBOLS = ["MarionetteServer"];
|
|
const SPECIAL_POWERS_PREF = "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer";
|
|
const CONTENT_LISTENER_PREF = "marionette.contentListener";
|
|
|
|
/**
|
|
* Bootstraps Marionette and handles incoming client connections.
|
|
*
|
|
* Once started, it opens a TCP socket sporting the debugger transport
|
|
* protocol on the provided port. For every new client a Dispatcher is
|
|
* created.
|
|
*
|
|
* @param {number} port
|
|
* Port for server to listen to.
|
|
* @param {boolean} forceLocal
|
|
* Listen only to connections from loopback if true. If false,
|
|
* accept all connections.
|
|
*/
|
|
this.MarionetteServer = function(port, forceLocal) {
|
|
this.port = port;
|
|
this.forceLocal = forceLocal;
|
|
this.conns = {};
|
|
this.nextConnId = 0;
|
|
this.alive = false;
|
|
};
|
|
|
|
/**
|
|
* Initialises the Marionette server by loading in the special powers
|
|
* which is required to provide some automation-only features.
|
|
*/
|
|
MarionetteServer.prototype.init = function() {
|
|
// SpecialPowers requires insecure automation-only features that we put behind a pref
|
|
Services.prefs.setBoolPref(SPECIAL_POWERS_PREF, true);
|
|
let specialpowers = {};
|
|
loader.loadSubScript(
|
|
"chrome://specialpowers/content/SpecialPowersObserver.js", specialpowers);
|
|
specialpowers.specialPowersObserver = new specialpowers.SpecialPowersObserver();
|
|
specialpowers.specialPowersObserver.init();
|
|
};
|
|
|
|
/**
|
|
* Function that takes an Emulator and produces a GeckoDriver.
|
|
*
|
|
* Determines application name and device type to initialise the driver
|
|
* with. Also bypasses offline status if the device is a qemu or panda
|
|
* type device.
|
|
*
|
|
* @return {GeckoDriver}
|
|
* A driver instance.
|
|
*/
|
|
MarionetteServer.prototype.driverFactory = function(emulator) {
|
|
let appName = isMulet() ? "B2G" : Services.appinfo.name;
|
|
let qemu = "0";
|
|
let device = null;
|
|
let bypassOffline = false;
|
|
|
|
try {
|
|
Cu.import("resource://gre/modules/systemlibs.js");
|
|
qemu = libcutils.property_get("ro.kernel.qemu");
|
|
logger.debug("B2G emulator: " + (qemu == "1" ? "yes" : "no"));
|
|
device = libcutils.property_get("ro.product.device");
|
|
logger.debug("Device detected is " + device);
|
|
bypassOffline = (qemu == "1" || device == "panda");
|
|
} catch (e) {}
|
|
|
|
if (qemu == "1") {
|
|
device = "qemu";
|
|
}
|
|
if (!device) {
|
|
device = "desktop";
|
|
}
|
|
|
|
Services.prefs.setBoolPref(CONTENT_LISTENER_PREF, false);
|
|
|
|
if (bypassOffline) {
|
|
logger.debug("Bypassing offline status");
|
|
Services.prefs.setBoolPref("network.gonk.manage-offline-status", false);
|
|
Services.io.manageOfflineStatus = false;
|
|
Services.io.offline = false;
|
|
}
|
|
|
|
return new GeckoDriver(appName, device, emulator);
|
|
};
|
|
|
|
MarionetteServer.prototype.start = function() {
|
|
if (this.alive) {
|
|
return;
|
|
}
|
|
this.init();
|
|
let flags = Ci.nsIServerSocket.KeepWhenOffline;
|
|
if (this.forceLocal) {
|
|
flags |= Ci.nsIServerSocket.LoopbackOnly;
|
|
}
|
|
this.listener = new ServerSocket(this.port, flags, 0);
|
|
this.listener.asyncListen(this);
|
|
this.alive = true;
|
|
};
|
|
|
|
MarionetteServer.prototype.stop = function() {
|
|
if (!this.alive) {
|
|
return;
|
|
}
|
|
this.closeListener();
|
|
this.alive = false;
|
|
};
|
|
|
|
MarionetteServer.prototype.closeListener = function() {
|
|
this.listener.close();
|
|
this.listener = null;
|
|
};
|
|
|
|
MarionetteServer.prototype.onSocketAccepted = function(
|
|
serverSocket, clientSocket) {
|
|
let input = clientSocket.openInputStream(0, 0, 0);
|
|
let output = clientSocket.openOutputStream(0, 0, 0);
|
|
let transport = new DebuggerTransport(input, output);
|
|
let connId = "conn" + this.nextConnId++;
|
|
|
|
let stopSignal = () => this.stop();
|
|
let dispatcher = new Dispatcher(connId, transport, this.driverFactory, stopSignal);
|
|
dispatcher.onclose = this.onConnectionClosed.bind(this);
|
|
this.conns[connId] = dispatcher;
|
|
|
|
logger.info(`Accepted connection ${connId} from ${clientSocket.host}:${clientSocket.port}`);
|
|
|
|
// Create a root actor for the connection and send the hello packet
|
|
dispatcher.sayHello();
|
|
transport.ready();
|
|
};
|
|
|
|
MarionetteServer.prototype.onConnectionClosed = function(conn) {
|
|
let id = conn.id;
|
|
delete this.conns[id];
|
|
logger.info(`Closed connection ${id}`);
|
|
};
|
|
|
|
function isMulet() {
|
|
try {
|
|
return Services.prefs.getBoolPref("b2g.is_mulet");
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|