2012-03-22 19:19:57 +04:00
|
|
|
/* 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/. */
|
|
|
|
|
2015-03-20 00:12:58 +03:00
|
|
|
"use strict";
|
|
|
|
|
2019-01-17 21:18:31 +03:00
|
|
|
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|
|
|
const { XPCOMUtils } = ChromeUtils.import(
|
|
|
|
"resource://gre/modules/XPCOMUtils.jsm"
|
|
|
|
);
|
2017-03-09 14:12:53 +03:00
|
|
|
|
2019-01-17 21:18:31 +03:00
|
|
|
const { EnvironmentPrefs, MarionettePrefs } = ChromeUtils.import(
|
|
|
|
"chrome://marionette/content/prefs.js",
|
|
|
|
null
|
|
|
|
);
|
2018-06-09 20:51:13 +03:00
|
|
|
|
|
|
|
XPCOMUtils.defineLazyModuleGetters(this, {
|
2018-06-06 16:38:36 +03:00
|
|
|
Log: "chrome://marionette/content/log.js",
|
2018-06-09 20:51:13 +03:00
|
|
|
Preferences: "resource://gre/modules/Preferences.jsm",
|
|
|
|
TCPListener: "chrome://marionette/content/server.js",
|
|
|
|
});
|
|
|
|
|
2018-06-06 16:38:36 +03:00
|
|
|
XPCOMUtils.defineLazyGetter(this, "log", Log.get);
|
2017-07-30 21:05:22 +03:00
|
|
|
|
2018-06-09 20:51:13 +03:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(
|
|
|
|
this,
|
|
|
|
"env",
|
|
|
|
"@mozilla.org/process/environment;1",
|
|
|
|
"nsIEnvironment"
|
|
|
|
);
|
|
|
|
|
2018-06-29 14:14:32 +03:00
|
|
|
const XMLURI_PARSE_ERROR =
|
|
|
|
"http://www.mozilla.org/newlayout/xml/parsererror.xml";
|
|
|
|
|
2019-11-26 16:23:29 +03:00
|
|
|
const NOTIFY_LISTENING = "remote-listening";
|
2017-03-09 14:12:53 +03:00
|
|
|
|
2017-04-15 03:50:29 +03:00
|
|
|
// Complements -marionette flag for starting the Marionette server.
|
|
|
|
// We also set this if Marionette is running in order to start the server
|
|
|
|
// again after a Firefox restart.
|
|
|
|
const ENV_ENABLED = "MOZ_MARIONETTE";
|
|
|
|
|
2017-03-09 14:12:53 +03:00
|
|
|
// Besides starting based on existing prefs in a profile and a command
|
|
|
|
// line flag, we also support inheriting prefs out of an env var, and to
|
|
|
|
// start Marionette that way.
|
|
|
|
//
|
|
|
|
// This allows marionette prefs to persist when we do a restart into
|
|
|
|
// a different profile in order to test things like Firefox refresh.
|
|
|
|
// The environment variable itself, if present, is interpreted as a
|
|
|
|
// JSON structure, with the keys mapping to preference names in the
|
|
|
|
// "marionette." branch, and the values to the values of those prefs. So
|
2017-04-13 17:08:14 +03:00
|
|
|
// something like {"port": 4444} would result in the marionette.port
|
|
|
|
// pref being set to 4444.
|
2017-04-15 03:50:29 +03:00
|
|
|
const ENV_PRESERVE_PREFS = "MOZ_MARIONETTE_PREF_STATE_ACROSS_RESTARTS";
|
2016-04-08 19:17:47 +03:00
|
|
|
|
2018-11-27 23:12:04 +03:00
|
|
|
// ALL CHANGES TO THIS LIST MUST HAVE REVIEW FROM A MARIONETTE PEER!
|
|
|
|
//
|
2018-02-26 23:31:19 +03:00
|
|
|
// Marionette sets preferences recommended for automation when it starts,
|
|
|
|
// unless marionette.prefs.recommended has been set to false.
|
2018-11-27 23:12:04 +03:00
|
|
|
//
|
|
|
|
// All prefs as added here have immediate effect, and don't require a restart
|
|
|
|
// nor have to be set in the profile before the application starts. If such a
|
|
|
|
// latter preference has to be added, it needs to be done for the client like
|
|
|
|
// Marionette client (geckoinstance.py), or geckodriver (prefs.rs).
|
|
|
|
//
|
|
|
|
// Note: Clients do not always use the latest version of the application. As
|
|
|
|
// such backward compatibility has to be ensured at least for the last three
|
|
|
|
// releases.
|
2018-02-26 23:31:19 +03:00
|
|
|
const RECOMMENDED_PREFS = new Map([
|
2018-03-08 18:47:09 +03:00
|
|
|
// Make sure Shield doesn't hit the network.
|
|
|
|
["app.normandy.api_url", ""],
|
|
|
|
|
2018-12-05 11:12:46 +03:00
|
|
|
// Disable automatically upgrading Firefox
|
|
|
|
//
|
|
|
|
// Note: This preference should have already been set by the client when
|
|
|
|
// creating the profile. But if not and to absolutely make sure that updates
|
|
|
|
// of Firefox aren't downloaded and applied, enforce its presence.
|
|
|
|
["app.update.disabledForTesting", true],
|
|
|
|
|
2018-02-26 23:31:19 +03:00
|
|
|
// Increase the APZ content response timeout in tests to 1 minute.
|
|
|
|
// This is to accommodate the fact that test environments tends to be
|
|
|
|
// slower than production environments (with the b2g emulator being
|
|
|
|
// the slowest of them all), resulting in the production timeout value
|
|
|
|
// sometimes being exceeded and causing false-positive test failures.
|
|
|
|
//
|
|
|
|
// (bug 1176798, bug 1177018, bug 1210465)
|
|
|
|
["apz.content_response_timeout", 60000],
|
|
|
|
|
2019-07-22 10:57:25 +03:00
|
|
|
// Don't show the content blocking introduction panel.
|
|
|
|
// We use a larger number than the default 22 to have some buffer
|
|
|
|
// This can be removed once Firefox 69 and 68 ESR and are no longer supported.
|
|
|
|
["browser.contentblocking.introCount", 99],
|
|
|
|
|
2018-02-26 23:31:19 +03:00
|
|
|
// Indicate that the download panel has been shown once so that
|
|
|
|
// whichever download test runs first doesn't show the popup
|
|
|
|
// inconsistently.
|
|
|
|
["browser.download.panel.shown", true],
|
|
|
|
|
2018-11-12 22:59:45 +03:00
|
|
|
// Always display a blank page
|
|
|
|
["browser.newtabpage.enabled", false],
|
|
|
|
|
2018-02-26 23:31:19 +03:00
|
|
|
// Background thumbnails in particular cause grief, and disabling
|
|
|
|
// thumbnails in general cannot hurt
|
|
|
|
["browser.pagethumbnails.capturing_disabled", true],
|
|
|
|
|
|
|
|
// Disable safebrowsing components.
|
|
|
|
//
|
|
|
|
// These should also be set in the profile prior to starting Firefox,
|
|
|
|
// as it is picked up at runtime.
|
|
|
|
["browser.safebrowsing.blockedURIs.enabled", false],
|
|
|
|
["browser.safebrowsing.downloads.enabled", false],
|
|
|
|
["browser.safebrowsing.passwords.enabled", false],
|
|
|
|
["browser.safebrowsing.malware.enabled", false],
|
|
|
|
["browser.safebrowsing.phishing.enabled", false],
|
|
|
|
|
|
|
|
// Disable updates to search engines.
|
|
|
|
//
|
|
|
|
// Should be set in profile.
|
|
|
|
["browser.search.update", false],
|
|
|
|
|
|
|
|
// Do not restore the last open set of tabs if the browser has crashed
|
|
|
|
["browser.sessionstore.resume_from_crash", false],
|
|
|
|
|
|
|
|
// Don't check for the default web browser during startup.
|
|
|
|
//
|
|
|
|
// These should also be set in the profile prior to starting Firefox,
|
|
|
|
// as it is picked up at runtime.
|
|
|
|
["browser.shell.checkDefaultBrowser", false],
|
|
|
|
|
|
|
|
// Do not redirect user when a milstone upgrade of Firefox is detected
|
|
|
|
["browser.startup.homepage_override.mstone", "ignore"],
|
|
|
|
|
2018-06-05 12:37:27 +03:00
|
|
|
// Do not close the window when the last tab gets closed
|
|
|
|
["browser.tabs.closeWindowWithLastTab", false],
|
|
|
|
|
|
|
|
// Do not allow background tabs to be zombified on Android, otherwise for
|
|
|
|
// tests that open additional tabs, the test harness tab itself might get
|
2018-02-26 23:31:19 +03:00
|
|
|
// unloaded
|
|
|
|
["browser.tabs.disableBackgroundZombification", false],
|
|
|
|
|
2019-06-12 16:45:32 +03:00
|
|
|
// Bug 1557457: Disable because modal dialogs might not appear in Firefox
|
|
|
|
["browser.tabs.remote.separatePrivilegedContentProcess", false],
|
|
|
|
|
2019-06-07 16:33:25 +03:00
|
|
|
// Don't unload tabs when available memory is running low
|
|
|
|
["browser.tabs.unloadOnLowMemory", false],
|
|
|
|
|
2018-06-05 12:37:27 +03:00
|
|
|
// Do not warn when closing all open tabs
|
|
|
|
["browser.tabs.warnOnClose", false],
|
|
|
|
|
2018-02-26 23:31:19 +03:00
|
|
|
// Do not warn when closing all other open tabs
|
|
|
|
["browser.tabs.warnOnCloseOtherTabs", false],
|
|
|
|
|
|
|
|
// Do not warn when multiple tabs will be opened
|
|
|
|
["browser.tabs.warnOnOpen", false],
|
|
|
|
|
|
|
|
// Disable first run splash page on Windows 10
|
|
|
|
["browser.usedOnWindows10.introURL", ""],
|
|
|
|
|
|
|
|
// Disable the UI tour.
|
|
|
|
//
|
|
|
|
// Should be set in profile.
|
|
|
|
["browser.uitour.enabled", false],
|
|
|
|
|
|
|
|
// Turn off search suggestions in the location bar so as not to trigger
|
|
|
|
// network connections.
|
|
|
|
["browser.urlbar.suggest.searches", false],
|
|
|
|
|
2018-06-05 12:37:27 +03:00
|
|
|
// Do not warn on quitting Firefox
|
|
|
|
["browser.warnOnQuit", false],
|
2018-02-26 23:31:19 +03:00
|
|
|
|
|
|
|
// Do not show datareporting policy notifications which can
|
|
|
|
// interfere with tests
|
|
|
|
[
|
|
|
|
"datareporting.healthreport.documentServerURI",
|
|
|
|
"http://%(server)s/dummy/healthreport/",
|
|
|
|
],
|
|
|
|
["datareporting.healthreport.logging.consoleEnabled", false],
|
|
|
|
["datareporting.healthreport.service.enabled", false],
|
|
|
|
["datareporting.healthreport.service.firstRun", false],
|
|
|
|
["datareporting.healthreport.uploadEnabled", false],
|
|
|
|
["datareporting.policy.dataSubmissionEnabled", false],
|
|
|
|
["datareporting.policy.dataSubmissionPolicyAccepted", false],
|
|
|
|
["datareporting.policy.dataSubmissionPolicyBypassNotification", true],
|
|
|
|
|
2018-04-19 15:47:32 +03:00
|
|
|
// Automatically unload beforeunload alerts
|
|
|
|
["dom.disable_beforeunload", true],
|
|
|
|
|
2018-02-26 23:31:19 +03:00
|
|
|
// Disable popup-blocker
|
|
|
|
["dom.disable_open_during_load", false],
|
|
|
|
|
|
|
|
// Enabling the support for File object creation in the content process
|
|
|
|
["dom.file.createInChild", true],
|
|
|
|
|
|
|
|
// Disable the ProcessHangMonitor
|
|
|
|
["dom.ipc.reportProcessHangs", false],
|
|
|
|
|
|
|
|
// Disable slow script dialogues
|
|
|
|
["dom.max_chrome_script_run_time", 0],
|
|
|
|
["dom.max_script_run_time", 0],
|
|
|
|
|
2019-06-05 11:11:38 +03:00
|
|
|
// DOM Push
|
|
|
|
["dom.push.connection.enabled", false],
|
|
|
|
|
2018-02-26 23:31:19 +03:00
|
|
|
// Only load extensions from the application and user profile
|
|
|
|
// AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
|
|
|
|
//
|
|
|
|
// Should be set in profile.
|
|
|
|
["extensions.autoDisableScopes", 0],
|
|
|
|
["extensions.enabledScopes", 5],
|
|
|
|
|
|
|
|
// Disable metadata caching for installed add-ons by default
|
|
|
|
["extensions.getAddons.cache.enabled", false],
|
|
|
|
|
|
|
|
// Disable installing any distribution extensions or add-ons.
|
|
|
|
// Should be set in profile.
|
|
|
|
["extensions.installDistroAddons", false],
|
|
|
|
|
|
|
|
// Turn off extension updates so they do not bother tests
|
|
|
|
["extensions.update.enabled", false],
|
|
|
|
["extensions.update.notifyUser", false],
|
|
|
|
|
|
|
|
// Make sure opening about:addons will not hit the network
|
|
|
|
["extensions.webservice.discoverURL", "http://%(server)s/dummy/discoveryURL"],
|
|
|
|
|
|
|
|
// Allow the application to have focus even it runs in the background
|
|
|
|
["focusmanager.testmode", true],
|
|
|
|
|
|
|
|
// Disable useragent updates
|
|
|
|
["general.useragent.updates.enabled", false],
|
|
|
|
|
|
|
|
// Always use network provider for geolocation tests so we bypass the
|
|
|
|
// macOS dialog raised by the corelocation provider
|
|
|
|
["geo.provider.testing", true],
|
|
|
|
|
|
|
|
// Do not scan Wifi
|
|
|
|
["geo.wifi.scan", false],
|
|
|
|
|
|
|
|
// Show chrome errors and warnings in the error console
|
|
|
|
["javascript.options.showInConsole", true],
|
|
|
|
|
2018-06-05 12:37:27 +03:00
|
|
|
// Do not prompt with long usernames or passwords in URLs
|
|
|
|
["network.http.phishy-userpass-length", 255],
|
|
|
|
|
2018-02-26 23:31:19 +03:00
|
|
|
// Do not prompt for temporary redirects
|
|
|
|
["network.http.prompt-temp-redirect", false],
|
|
|
|
|
|
|
|
// Disable speculative connections so they are not reported as leaking
|
|
|
|
// when they are hanging around
|
|
|
|
["network.http.speculative-parallel-limit", 0],
|
|
|
|
|
|
|
|
// Do not automatically switch between offline and online
|
|
|
|
["network.manage-offline-status", false],
|
|
|
|
|
|
|
|
// Make sure SNTP requests do not hit the network
|
|
|
|
["network.sntp.pools", "%(server)s"],
|
2019-06-05 11:11:38 +03:00
|
|
|
|
|
|
|
// Privacy and Tracking Protection
|
|
|
|
["privacy.trackingprotection.enabled", false],
|
2018-02-26 23:31:19 +03:00
|
|
|
|
2019-03-14 02:37:01 +03:00
|
|
|
// Don't do network connections for mitm priming
|
|
|
|
["security.certerrors.mitm.priming.enabled", false],
|
|
|
|
|
2018-02-26 23:31:19 +03:00
|
|
|
// Local documents have access to all other local documents,
|
|
|
|
// including directory listings
|
|
|
|
["security.fileuri.strict_origin_policy", false],
|
|
|
|
|
|
|
|
// Tests do not wait for the notification button security delay
|
|
|
|
["security.notification_enable_delay", 0],
|
|
|
|
|
|
|
|
// Ensure blocklist updates do not hit the network
|
|
|
|
["services.settings.server", "http://%(server)s/dummy/blocklist/"],
|
|
|
|
|
|
|
|
// Do not automatically fill sign-in forms with known usernames and
|
|
|
|
// passwords
|
|
|
|
["signon.autofillForms", false],
|
|
|
|
|
|
|
|
// Disable password capture, so that tests that include forms are not
|
|
|
|
// influenced by the presence of the persistent doorhanger notification
|
|
|
|
["signon.rememberSignons", false],
|
|
|
|
|
|
|
|
// Disable first-run welcome page
|
|
|
|
["startup.homepage_welcome_url", "about:blank"],
|
|
|
|
["startup.homepage_welcome_url.additional", ""],
|
|
|
|
|
2018-11-12 22:59:45 +03:00
|
|
|
// Disable browser animations (tabs, fullscreen, sliding alerts)
|
|
|
|
["toolkit.cosmeticAnimations.enabled", false],
|
|
|
|
|
2018-02-26 23:31:19 +03:00
|
|
|
// Prevent starting into safe mode after application crashes
|
|
|
|
["toolkit.startup.max_resumed_crashes", -1],
|
|
|
|
]);
|
|
|
|
|
2018-01-27 22:34:32 +03:00
|
|
|
const isRemote =
|
|
|
|
Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
|
|
|
|
|
2018-06-09 20:57:03 +03:00
|
|
|
class MarionetteParentProcess {
|
2018-01-27 21:39:47 +03:00
|
|
|
constructor() {
|
|
|
|
this.server = null;
|
2017-03-09 20:57:26 +03:00
|
|
|
|
2018-01-27 21:39:47 +03:00
|
|
|
// holds reference to ChromeWindow
|
|
|
|
// used to run GFX sanity tests on Windows
|
|
|
|
this.gfxWindow = null;
|
2017-03-09 20:57:26 +03:00
|
|
|
|
2018-01-27 21:39:47 +03:00
|
|
|
// indicates that all pending window checks have been completed
|
|
|
|
// and that we are ready to start the Marionette server
|
|
|
|
this.finalUIStartup = false;
|
2017-03-09 20:57:26 +03:00
|
|
|
|
2018-02-26 23:31:19 +03:00
|
|
|
this.alteredPrefs = new Set();
|
2018-01-27 22:03:18 +03:00
|
|
|
|
2019-11-01 23:21:48 +03:00
|
|
|
if (env.exists(ENV_ENABLED)) {
|
|
|
|
MarionettePrefs.enabled = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
|
|
this,
|
|
|
|
"enabled",
|
|
|
|
"marionette.enabled",
|
|
|
|
false,
|
|
|
|
(aPreference, previousValue, newValue) => {
|
|
|
|
if (newValue) {
|
|
|
|
this.init(false);
|
|
|
|
} else {
|
|
|
|
this.uninit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
2018-01-27 22:34:32 +03:00
|
|
|
Services.ppmm.addMessageListener("Marionette:IsRunning", this);
|
2017-07-05 11:33:23 +03:00
|
|
|
}
|
2017-03-09 14:12:53 +03:00
|
|
|
|
2018-01-27 21:46:17 +03:00
|
|
|
get running() {
|
2018-05-14 21:51:56 +03:00
|
|
|
return !!this.server && this.server.alive;
|
2018-01-27 21:46:17 +03:00
|
|
|
}
|
|
|
|
|
2018-01-27 22:34:32 +03:00
|
|
|
receiveMessage({ name }) {
|
|
|
|
switch (name) {
|
|
|
|
case "Marionette:IsRunning":
|
|
|
|
return this.running;
|
|
|
|
|
|
|
|
default:
|
2018-06-09 20:57:03 +03:00
|
|
|
log.warn("Unknown IPC message to parent process: " + name);
|
2018-01-27 22:34:32 +03:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-27 21:39:47 +03:00
|
|
|
observe(subject, topic) {
|
2018-11-29 22:31:38 +03:00
|
|
|
log.trace(`Received observer notification ${topic}`);
|
2018-01-27 21:39:47 +03:00
|
|
|
|
|
|
|
switch (topic) {
|
|
|
|
case "profile-after-change":
|
|
|
|
Services.obs.addObserver(this, "command-line-startup");
|
2018-06-29 14:14:32 +03:00
|
|
|
Services.obs.addObserver(this, "toplevel-window-ready");
|
2019-02-04 21:15:32 +03:00
|
|
|
Services.obs.addObserver(this, "marionette-startup-requested");
|
2017-08-10 19:04:47 +03:00
|
|
|
|
2018-04-14 19:28:42 +03:00
|
|
|
for (let [pref, value] of EnvironmentPrefs.from(ENV_PRESERVE_PREFS)) {
|
|
|
|
Preferences.set(pref, value);
|
|
|
|
}
|
2018-01-27 21:39:47 +03:00
|
|
|
break;
|
2013-10-15 22:20:35 +04:00
|
|
|
|
2018-01-27 21:39:47 +03:00
|
|
|
// In safe mode the command line handlers are getting parsed after the
|
|
|
|
// safe mode dialog has been closed. To allow Marionette to start
|
|
|
|
// earlier, use the CLI startup observer notification for
|
|
|
|
// special-cased handlers, which gets fired before the dialog appears.
|
|
|
|
case "command-line-startup":
|
2017-03-09 14:12:53 +03:00
|
|
|
Services.obs.removeObserver(this, topic);
|
2018-01-27 21:53:02 +03:00
|
|
|
|
|
|
|
if (!this.enabled && subject.handleFlag("marionette", false)) {
|
2019-11-01 23:21:48 +03:00
|
|
|
MarionettePrefs.enabled = true;
|
2018-01-27 21:53:02 +03:00
|
|
|
}
|
2017-03-07 21:38:51 +03:00
|
|
|
|
2018-01-27 21:39:47 +03:00
|
|
|
// We want to suppress the modal dialog that's shown
|
|
|
|
// when starting up in safe-mode to enable testing.
|
|
|
|
if (this.enabled && Services.appinfo.inSafeMode) {
|
|
|
|
Services.obs.addObserver(this, "domwindowopened");
|
2017-03-07 21:38:51 +03:00
|
|
|
}
|
|
|
|
|
2018-01-27 21:39:47 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case "domwindowclosed":
|
|
|
|
if (this.gfxWindow === null || subject === this.gfxWindow) {
|
|
|
|
Services.obs.removeObserver(this, topic);
|
2019-03-15 15:51:11 +03:00
|
|
|
Services.obs.removeObserver(this, "toplevel-window-ready");
|
2017-03-07 21:38:51 +03:00
|
|
|
|
2018-02-26 23:36:29 +03:00
|
|
|
Services.obs.addObserver(this, "xpcom-will-shutdown");
|
2019-03-15 15:51:11 +03:00
|
|
|
|
|
|
|
this.finalUIStartup = true;
|
|
|
|
this.init();
|
2018-01-27 21:39:47 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "domwindowopened":
|
|
|
|
Services.obs.removeObserver(this, topic);
|
|
|
|
this.suppressSafeModeDialog(subject);
|
|
|
|
break;
|
2017-03-07 21:38:51 +03:00
|
|
|
|
2018-06-29 14:14:32 +03:00
|
|
|
case "toplevel-window-ready":
|
|
|
|
subject.addEventListener(
|
|
|
|
"load",
|
|
|
|
ev => {
|
|
|
|
if (ev.target.documentElement.namespaceURI == XMLURI_PARSE_ERROR) {
|
|
|
|
Services.obs.removeObserver(this, topic);
|
2019-07-05 12:01:24 +03:00
|
|
|
|
2018-06-29 14:14:32 +03:00
|
|
|
let parserError = ev.target.querySelector("parsererror");
|
|
|
|
log.fatal(parserError.textContent);
|
|
|
|
this.uninit();
|
|
|
|
Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{ once: true }
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
2019-03-15 15:51:11 +03:00
|
|
|
case "marionette-startup-requested":
|
2018-01-27 21:39:47 +03:00
|
|
|
Services.obs.removeObserver(this, topic);
|
|
|
|
|
|
|
|
// When Firefox starts on Windows, an additional GFX sanity test
|
|
|
|
// window may appear off-screen. Marionette should wait for it
|
|
|
|
// to close.
|
2018-08-19 04:13:14 +03:00
|
|
|
for (let win of Services.wm.getEnumerator(null)) {
|
2018-01-27 21:39:47 +03:00
|
|
|
if (
|
|
|
|
win.document.documentURI ==
|
|
|
|
"chrome://gfxsanity/content/sanityparent.html"
|
|
|
|
) {
|
|
|
|
this.gfxWindow = win;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.gfxWindow) {
|
2018-11-29 22:31:38 +03:00
|
|
|
log.trace(
|
|
|
|
"GFX sanity window detected, waiting until it has been closed..."
|
|
|
|
);
|
2018-01-27 21:39:47 +03:00
|
|
|
Services.obs.addObserver(this, "domwindowclosed");
|
|
|
|
} else {
|
2019-03-15 15:51:11 +03:00
|
|
|
Services.obs.removeObserver(this, "toplevel-window-ready");
|
|
|
|
|
2018-02-26 23:36:29 +03:00
|
|
|
Services.obs.addObserver(this, "xpcom-will-shutdown");
|
2018-01-27 21:39:47 +03:00
|
|
|
|
2019-03-15 15:51:11 +03:00
|
|
|
this.finalUIStartup = true;
|
|
|
|
this.init();
|
|
|
|
}
|
2018-01-27 21:39:47 +03:00
|
|
|
|
2019-02-04 21:15:32 +03:00
|
|
|
break;
|
|
|
|
|
2018-02-26 23:36:29 +03:00
|
|
|
case "xpcom-will-shutdown":
|
|
|
|
Services.obs.removeObserver(this, "xpcom-will-shutdown");
|
2018-01-27 21:39:47 +03:00
|
|
|
this.uninit();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
suppressSafeModeDialog(win) {
|
|
|
|
win.addEventListener(
|
|
|
|
"load",
|
|
|
|
() => {
|
2019-12-10 21:14:10 +03:00
|
|
|
let dialog = win.document.getElementById("safeModeDialog");
|
|
|
|
if (dialog) {
|
2018-01-27 21:39:47 +03:00
|
|
|
// accept the dialog to start in safe-mode
|
2018-11-29 22:31:38 +03:00
|
|
|
log.trace("Safe mode detected, supressing dialog");
|
2018-01-27 21:39:47 +03:00
|
|
|
win.setTimeout(() => {
|
2019-12-10 21:14:10 +03:00
|
|
|
dialog.getButton("accept").click();
|
2018-01-27 21:39:47 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{ once: true }
|
|
|
|
);
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
|
|
|
|
2018-06-09 20:41:01 +03:00
|
|
|
init(quit = true) {
|
2018-01-27 21:39:47 +03:00
|
|
|
if (this.running || !this.enabled || !this.finalUIStartup) {
|
2018-05-10 19:20:17 +03:00
|
|
|
log.debug(
|
|
|
|
`Init aborted (running=${this.running}, ` +
|
|
|
|
`enabled=${this.enabled}, finalUIStartup=${this.finalUIStartup})`
|
|
|
|
);
|
2018-01-27 21:39:47 +03:00
|
|
|
return;
|
2012-03-22 19:19:57 +04:00
|
|
|
}
|
|
|
|
|
2018-11-29 22:31:38 +03:00
|
|
|
log.trace(
|
|
|
|
`Waiting until startup recorder finished recording startup scripts...`
|
|
|
|
);
|
2018-01-27 21:39:47 +03:00
|
|
|
Services.tm.idleDispatchToMainThread(async () => {
|
|
|
|
let startupRecorder = Promise.resolve();
|
|
|
|
if ("@mozilla.org/test/startuprecorder;1" in Cc) {
|
|
|
|
startupRecorder = Cc["@mozilla.org/test/startuprecorder;1"].getService()
|
|
|
|
.wrappedJSObject.done;
|
|
|
|
}
|
|
|
|
await startupRecorder;
|
2018-11-29 22:31:38 +03:00
|
|
|
log.trace(`All scripts recorded.`);
|
2018-01-27 21:39:47 +03:00
|
|
|
|
2018-04-14 19:28:42 +03:00
|
|
|
if (MarionettePrefs.recommendedPrefs) {
|
2018-02-26 23:31:19 +03:00
|
|
|
for (let [k, v] of RECOMMENDED_PREFS) {
|
|
|
|
if (!Preferences.isSet(k)) {
|
|
|
|
log.debug(`Setting recommended pref ${k} to ${v}`);
|
|
|
|
Preferences.set(k, v);
|
|
|
|
this.alteredPrefs.add(k);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-27 21:39:47 +03:00
|
|
|
try {
|
2018-06-09 20:51:13 +03:00
|
|
|
this.server = new TCPListener(MarionettePrefs.port);
|
|
|
|
this.server.start();
|
2018-01-27 21:39:47 +03:00
|
|
|
} catch (e) {
|
|
|
|
log.fatal("Remote protocol server failed to start", e);
|
2018-02-26 23:37:58 +03:00
|
|
|
this.uninit();
|
2018-06-09 20:41:01 +03:00
|
|
|
if (quit) {
|
|
|
|
Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
|
|
|
|
}
|
2018-06-06 20:31:28 +03:00
|
|
|
return;
|
2018-01-27 21:39:47 +03:00
|
|
|
}
|
2018-01-27 21:49:03 +03:00
|
|
|
|
2018-02-26 23:34:54 +03:00
|
|
|
env.set(ENV_ENABLED, "1");
|
2019-11-26 16:23:29 +03:00
|
|
|
Services.obs.notifyObservers(this, NOTIFY_LISTENING, true);
|
|
|
|
log.debug("Marionette is listening");
|
2018-01-27 21:39:47 +03:00
|
|
|
});
|
2015-03-20 00:12:58 +03:00
|
|
|
}
|
|
|
|
|
2018-01-27 21:39:47 +03:00
|
|
|
uninit() {
|
2018-06-06 20:34:32 +03:00
|
|
|
for (let k of this.alteredPrefs) {
|
|
|
|
log.debug(`Resetting recommended pref ${k}`);
|
|
|
|
Preferences.reset(k);
|
|
|
|
}
|
|
|
|
this.alteredPrefs.clear();
|
|
|
|
|
2018-01-27 21:46:17 +03:00
|
|
|
if (this.running) {
|
|
|
|
this.server.stop();
|
2019-11-26 16:23:29 +03:00
|
|
|
Services.obs.notifyObservers(this, NOTIFY_LISTENING);
|
|
|
|
log.debug("Marionette stopped listening");
|
2018-01-22 20:21:52 +03:00
|
|
|
}
|
2018-01-27 21:39:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
get QueryInterface() {
|
2018-04-23 06:55:06 +03:00
|
|
|
return ChromeUtils.generateQI([
|
2018-01-27 21:39:47 +03:00
|
|
|
Ci.nsICommandLineHandler,
|
|
|
|
Ci.nsIMarionette,
|
2018-01-27 22:03:18 +03:00
|
|
|
Ci.nsIObserver,
|
2018-01-27 21:39:47 +03:00
|
|
|
]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-27 22:34:32 +03:00
|
|
|
class MarionetteContentProcess {
|
|
|
|
get running() {
|
|
|
|
let reply = Services.cpmm.sendSyncMessage("Marionette:IsRunning");
|
|
|
|
if (reply.length == 0) {
|
2018-06-09 20:57:03 +03:00
|
|
|
log.warn("No reply from parent process");
|
2018-01-27 22:34:32 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return reply[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
get QueryInterface() {
|
2018-04-23 06:55:06 +03:00
|
|
|
return ChromeUtils.generateQI([Ci.nsIMarionette]);
|
2018-01-27 22:34:32 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-27 21:39:47 +03:00
|
|
|
const MarionetteFactory = {
|
2018-01-27 22:34:32 +03:00
|
|
|
instance_: null,
|
|
|
|
|
2018-01-27 21:39:47 +03:00
|
|
|
createInstance(outer, iid) {
|
|
|
|
if (outer) {
|
|
|
|
throw Cr.NS_ERROR_NO_AGGREGATION;
|
2018-01-22 20:21:52 +03:00
|
|
|
}
|
2018-01-27 21:39:47 +03:00
|
|
|
|
2018-01-27 22:34:32 +03:00
|
|
|
if (!this.instance_) {
|
|
|
|
if (isRemote) {
|
|
|
|
this.instance_ = new MarionetteContentProcess();
|
|
|
|
} else {
|
2018-06-09 20:57:03 +03:00
|
|
|
this.instance_ = new MarionetteParentProcess();
|
2018-01-27 22:34:32 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.instance_.QueryInterface(iid);
|
2018-01-27 21:39:47 +03:00
|
|
|
},
|
2015-03-20 00:12:58 +03:00
|
|
|
};
|
2012-03-22 19:19:57 +04:00
|
|
|
|
2018-01-27 21:39:47 +03:00
|
|
|
function Marionette() {}
|
|
|
|
|
|
|
|
Marionette.prototype = {
|
|
|
|
classDescription: "Marionette component",
|
|
|
|
classID: Components.ID("{786a1369-dca5-4adc-8486-33d23c88010a}"),
|
|
|
|
contractID: "@mozilla.org/remote/marionette;1",
|
|
|
|
|
2018-07-31 20:39:25 +03:00
|
|
|
/* eslint-disable-next-line camelcase */
|
2018-01-27 21:39:47 +03:00
|
|
|
_xpcom_factory: MarionetteFactory,
|
|
|
|
|
|
|
|
helpInfo: " --marionette Enable remote control server.\n",
|
2012-03-22 19:19:57 +04:00
|
|
|
};
|
|
|
|
|
2018-01-27 21:39:47 +03:00
|
|
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Marionette]);
|