Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | this.CC = Components.Constructor; |
michael@0 | 6 | this.Cc = Components.classes; |
michael@0 | 7 | this.Ci = Components.interfaces; |
michael@0 | 8 | this.Cu = Components.utils; |
michael@0 | 9 | |
michael@0 | 10 | const MARIONETTE_CONTRACTID = "@mozilla.org/marionette;1"; |
michael@0 | 11 | const MARIONETTE_CID = Components.ID("{786a1369-dca5-4adc-8486-33d23c88010a}"); |
michael@0 | 12 | const MARIONETTE_ENABLED_PREF = 'marionette.defaultPrefs.enabled'; |
michael@0 | 13 | const MARIONETTE_FORCELOCAL_PREF = 'marionette.force-local'; |
michael@0 | 14 | const MARIONETTE_LOG_PREF = 'marionette.logging'; |
michael@0 | 15 | |
michael@0 | 16 | this.ServerSocket = CC("@mozilla.org/network/server-socket;1", |
michael@0 | 17 | "nsIServerSocket", |
michael@0 | 18 | "initSpecialConnection"); |
michael@0 | 19 | |
michael@0 | 20 | Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
michael@0 | 21 | Cu.import("resource://gre/modules/Services.jsm"); |
michael@0 | 22 | Cu.import("resource://gre/modules/FileUtils.jsm"); |
michael@0 | 23 | Cu.import("resource://gre/modules/Log.jsm"); |
michael@0 | 24 | |
michael@0 | 25 | let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"] |
michael@0 | 26 | .getService(Ci.mozIJSSubScriptLoader); |
michael@0 | 27 | |
michael@0 | 28 | function MarionetteComponent() { |
michael@0 | 29 | this._loaded = false; |
michael@0 | 30 | this.observerService = Services.obs; |
michael@0 | 31 | |
michael@0 | 32 | // set up the logger |
michael@0 | 33 | this.logger = Log.repository.getLogger("Marionette"); |
michael@0 | 34 | this.logger.level = Log.Level["Trace"]; |
michael@0 | 35 | let dumper = false; |
michael@0 | 36 | #ifdef DEBUG |
michael@0 | 37 | dumper = true; |
michael@0 | 38 | #endif |
michael@0 | 39 | #ifdef MOZ_B2G |
michael@0 | 40 | dumper = true; |
michael@0 | 41 | #endif |
michael@0 | 42 | try { |
michael@0 | 43 | if (dumper || Services.prefs.getBoolPref(MARIONETTE_LOG_PREF)) { |
michael@0 | 44 | let formatter = new Log.BasicFormatter(); |
michael@0 | 45 | this.logger.addAppender(new Log.DumpAppender(formatter)); |
michael@0 | 46 | } |
michael@0 | 47 | } |
michael@0 | 48 | catch(e) {} |
michael@0 | 49 | } |
michael@0 | 50 | |
michael@0 | 51 | MarionetteComponent.prototype = { |
michael@0 | 52 | classDescription: "Marionette component", |
michael@0 | 53 | classID: MARIONETTE_CID, |
michael@0 | 54 | contractID: MARIONETTE_CONTRACTID, |
michael@0 | 55 | QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler, Ci.nsIObserver]), |
michael@0 | 56 | _xpcom_categories: [{category: "command-line-handler", entry: "b-marionette"}, |
michael@0 | 57 | {category: "profile-after-change", service: true}], |
michael@0 | 58 | appName: Services.appinfo.name, |
michael@0 | 59 | enabled: false, |
michael@0 | 60 | finalUiStartup: false, |
michael@0 | 61 | _marionetteServer: null, |
michael@0 | 62 | |
michael@0 | 63 | onSocketAccepted: function mc_onSocketAccepted(aSocket, aTransport) { |
michael@0 | 64 | this.logger.info("onSocketAccepted for Marionette dummy socket"); |
michael@0 | 65 | }, |
michael@0 | 66 | |
michael@0 | 67 | onStopListening: function mc_onStopListening(aSocket, status) { |
michael@0 | 68 | this.logger.info("onStopListening for Marionette dummy socket, code " + status); |
michael@0 | 69 | aSocket.close(); |
michael@0 | 70 | }, |
michael@0 | 71 | |
michael@0 | 72 | // Check cmdLine argument for --marionette |
michael@0 | 73 | handle: function mc_handle(cmdLine) { |
michael@0 | 74 | // If the CLI is there then lets do work otherwise nothing to see |
michael@0 | 75 | if (cmdLine.handleFlag("marionette", false)) { |
michael@0 | 76 | this.enabled = true; |
michael@0 | 77 | this.logger.info("marionette enabled via command-line"); |
michael@0 | 78 | this.init(); |
michael@0 | 79 | } |
michael@0 | 80 | }, |
michael@0 | 81 | |
michael@0 | 82 | observe: function mc_observe(aSubject, aTopic, aData) { |
michael@0 | 83 | switch (aTopic) { |
michael@0 | 84 | case "profile-after-change": |
michael@0 | 85 | // Using final-ui-startup as the xpcom category doesn't seem to work, |
michael@0 | 86 | // so we wait for that by adding an observer here. |
michael@0 | 87 | this.observerService.addObserver(this, "final-ui-startup", false); |
michael@0 | 88 | #ifdef ENABLE_MARIONETTE |
michael@0 | 89 | let enabledPref = false; |
michael@0 | 90 | try { |
michael@0 | 91 | enabledPref = Services.prefs.getBoolPref(MARIONETTE_ENABLED_PREF); |
michael@0 | 92 | } catch(e) {} |
michael@0 | 93 | if (enabledPref) { |
michael@0 | 94 | this.enabled = true; |
michael@0 | 95 | this.logger.info("marionette enabled via build flag and pref"); |
michael@0 | 96 | |
michael@0 | 97 | // We want to suppress the modal dialog that's shown |
michael@0 | 98 | // when starting up in safe-mode to enable testing. |
michael@0 | 99 | if (Services.appinfo.inSafeMode) { |
michael@0 | 100 | this.observerService.addObserver(this, "domwindowopened", false); |
michael@0 | 101 | } |
michael@0 | 102 | } |
michael@0 | 103 | #endif |
michael@0 | 104 | break; |
michael@0 | 105 | case "final-ui-startup": |
michael@0 | 106 | this.finalUiStartup = true; |
michael@0 | 107 | this.observerService.removeObserver(this, aTopic); |
michael@0 | 108 | this.observerService.addObserver(this, "xpcom-shutdown", false); |
michael@0 | 109 | this.init(); |
michael@0 | 110 | break; |
michael@0 | 111 | case "domwindowopened": |
michael@0 | 112 | this.observerService.removeObserver(this, aTopic); |
michael@0 | 113 | this._suppressSafeModeDialog(aSubject); |
michael@0 | 114 | break; |
michael@0 | 115 | case "xpcom-shutdown": |
michael@0 | 116 | this.observerService.removeObserver(this, "xpcom-shutdown"); |
michael@0 | 117 | this.uninit(); |
michael@0 | 118 | break; |
michael@0 | 119 | } |
michael@0 | 120 | }, |
michael@0 | 121 | |
michael@0 | 122 | _suppressSafeModeDialog: function mc_suppressSafeModeDialog(aWindow) { |
michael@0 | 123 | // Wait for the modal dialog to finish loading. |
michael@0 | 124 | aWindow.addEventListener("load", function onLoad() { |
michael@0 | 125 | aWindow.removeEventListener("load", onLoad); |
michael@0 | 126 | |
michael@0 | 127 | if (aWindow.document.getElementById("safeModeDialog")) { |
michael@0 | 128 | aWindow.setTimeout(() => { |
michael@0 | 129 | // Accept the dialog to start in safe-mode. |
michael@0 | 130 | aWindow.document.documentElement.getButton("accept").click(); |
michael@0 | 131 | }); |
michael@0 | 132 | } |
michael@0 | 133 | }); |
michael@0 | 134 | }, |
michael@0 | 135 | |
michael@0 | 136 | init: function mc_init() { |
michael@0 | 137 | if (!this._loaded && this.enabled && this.finalUiStartup) { |
michael@0 | 138 | this._loaded = true; |
michael@0 | 139 | |
michael@0 | 140 | let marionette_forcelocal = this.appName == 'B2G' ? false : true; |
michael@0 | 141 | try { |
michael@0 | 142 | marionette_forcelocal = Services.prefs.getBoolPref(MARIONETTE_FORCELOCAL_PREF); |
michael@0 | 143 | } |
michael@0 | 144 | catch(e) {} |
michael@0 | 145 | Services.prefs.setBoolPref(MARIONETTE_FORCELOCAL_PREF, marionette_forcelocal); |
michael@0 | 146 | |
michael@0 | 147 | if (!marionette_forcelocal) { |
michael@0 | 148 | // See bug 800138. Because the first socket that opens with |
michael@0 | 149 | // force-local=false fails, we open a dummy socket that will fail. |
michael@0 | 150 | // keepWhenOffline=true so that it still work when offline (local). |
michael@0 | 151 | // This allows the following attempt by Marionette to open a socket |
michael@0 | 152 | // to succeed. |
michael@0 | 153 | let insaneSacrificialGoat = new ServerSocket(666, Ci.nsIServerSocket.KeepWhenOffline, 4); |
michael@0 | 154 | insaneSacrificialGoat.asyncListen(this); |
michael@0 | 155 | } |
michael@0 | 156 | |
michael@0 | 157 | let port; |
michael@0 | 158 | try { |
michael@0 | 159 | port = Services.prefs.getIntPref('marionette.defaultPrefs.port'); |
michael@0 | 160 | } |
michael@0 | 161 | catch(e) { |
michael@0 | 162 | port = 2828; |
michael@0 | 163 | } |
michael@0 | 164 | try { |
michael@0 | 165 | loader.loadSubScript("chrome://marionette/content/marionette-server.js"); |
michael@0 | 166 | let forceLocal = Services.prefs.getBoolPref(MARIONETTE_FORCELOCAL_PREF); |
michael@0 | 167 | this._marionetteServer = new MarionetteServer(port, forceLocal); |
michael@0 | 168 | this.logger.info("Marionette server ready"); |
michael@0 | 169 | } |
michael@0 | 170 | catch(e) { |
michael@0 | 171 | this.logger.error('exception: ' + e.name + ', ' + e.message); |
michael@0 | 172 | } |
michael@0 | 173 | } |
michael@0 | 174 | }, |
michael@0 | 175 | |
michael@0 | 176 | uninit: function mc_uninit() { |
michael@0 | 177 | if (this._marionetteServer) { |
michael@0 | 178 | this._marionetteServer.closeListener(); |
michael@0 | 179 | } |
michael@0 | 180 | this._loaded = false; |
michael@0 | 181 | }, |
michael@0 | 182 | |
michael@0 | 183 | }; |
michael@0 | 184 | |
michael@0 | 185 | this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MarionetteComponent]); |