browser/devtools/framework/ToolboxProcess.jsm

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 "use strict";
     8 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
    10 const DBG_XUL = "chrome://browser/content/devtools/framework/toolbox-process-window.xul";
    11 const CHROME_DEBUGGER_PROFILE_NAME = "-chrome-debugger";
    13 Cu.import("resource://gre/modules/Services.jsm");
    14 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
    16 Cu.import("resource://gre/modules/devtools/Loader.jsm");
    17 let require = devtools.require;
    18 let Telemetry = require("devtools/shared/telemetry");
    19 let EventEmitter = require("devtools/toolkit/event-emitter");
    20 const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
    22 this.EXPORTED_SYMBOLS = ["BrowserToolboxProcess"];
    24 let processes = Set();
    26 /**
    27  * Constructor for creating a process that will hold a chrome toolbox.
    28  *
    29  * @param function aOnClose [optional]
    30  *        A function called when the process stops running.
    31  * @param function aOnRun [optional]
    32  *        A function called when the process starts running.
    33  * @param object aOptions [optional]
    34  *        An object with properties for configuring BrowserToolboxProcess.
    35  */
    36 this.BrowserToolboxProcess = function BrowserToolboxProcess(aOnClose, aOnRun, aOptions) {
    37   let emitter = new EventEmitter();
    38   this.on = emitter.on.bind(emitter);
    39   this.off = emitter.off.bind(emitter);
    40   this.once = emitter.once.bind(emitter);
    41   // Forward any events to the shared emitter.
    42   this.emit = function(...args) {
    43     emitter.emit(...args);
    44     BrowserToolboxProcess.emit(...args);
    45   }
    47   // If first argument is an object, use those properties instead of
    48   // all three arguments
    49   if (typeof aOnClose === "object") {
    50     if (aOnClose.onClose) {
    51       this.on("close", aOnClose.onClose);
    52     }
    53     if (aOnClose.onRun) {
    54       this.on("run", aOnClose.onRun);
    55     }
    56     this._options = aOnClose;
    57   } else {
    58     if (aOnClose) {
    59       this.on("close", aOnClose);
    60     }
    61     if (aOnRun) {
    62       this.on("run", aOnRun);
    63     }
    64     this._options = aOptions || {};
    65   }
    67   this._telemetry = new Telemetry();
    69   this.close = this.close.bind(this);
    70   Services.obs.addObserver(this.close, "quit-application", false);
    71   this._initServer();
    72   this._initProfile();
    73   this._create();
    75   processes.add(this);
    76 };
    78 EventEmitter.decorate(BrowserToolboxProcess);
    80 /**
    81  * Initializes and starts a chrome toolbox process.
    82  * @return object
    83  */
    84 BrowserToolboxProcess.init = function(aOnClose, aOnRun, aOptions) {
    85   return new BrowserToolboxProcess(aOnClose, aOnRun, aOptions);
    86 };
    88 /**
    89  * Passes a set of options to the BrowserAddonActors for the given ID.
    90  *
    91  * @param aId string
    92  *        The ID of the add-on to pass the options to
    93  * @param aOptions object
    94  *        The options.
    95  * @return a promise that will be resolved when complete.
    96  */
    97 BrowserToolboxProcess.setAddonOptions = function DSC_setAddonOptions(aId, aOptions) {
    98   let promises = [];
   100   for (let process of processes.values()) {
   101     promises.push(process.debuggerServer.setAddonOptions(aId, aOptions));
   102   }
   104   return promise.all(promises);
   105 };
   107 BrowserToolboxProcess.prototype = {
   108   /**
   109    * Initializes the debugger server.
   110    */
   111   _initServer: function() {
   112     dumpn("Initializing the chrome toolbox server.");
   114     if (!this.loader) {
   115       // Create a separate loader instance, so that we can be sure to receive a
   116       // separate instance of the DebuggingServer from the rest of the devtools.
   117       // This allows us to safely use the tools against even the actors and
   118       // DebuggingServer itself, especially since we can mark this loader as
   119       // invisible to the debugger (unlike the usual loader settings).
   120       this.loader = new DevToolsLoader();
   121       this.loader.invisibleToDebugger = true;
   122       this.loader.main("devtools/server/main");
   123       this.debuggerServer = this.loader.DebuggerServer;
   124       dumpn("Created a separate loader instance for the DebuggerServer.");
   126       // Forward interesting events.
   127       this.debuggerServer.on("connectionchange", this.emit.bind(this));
   128     }
   130     if (!this.debuggerServer.initialized) {
   131       this.debuggerServer.init();
   132       this.debuggerServer.addBrowserActors();
   133       dumpn("initialized and added the browser actors for the DebuggerServer.");
   134     }
   136     this.debuggerServer.openListener(Prefs.chromeDebuggingPort);
   138     dumpn("Finished initializing the chrome toolbox server.");
   139     dumpn("Started listening on port: " + Prefs.chromeDebuggingPort);
   140   },
   142   /**
   143    * Initializes a profile for the remote debugger process.
   144    */
   145   _initProfile: function() {
   146     dumpn("Initializing the chrome toolbox user profile.");
   148     let profileService = Cc["@mozilla.org/toolkit/profile-service;1"]
   149       .createInstance(Ci.nsIToolkitProfileService);
   151     let profileName;
   152     try {
   153       // Attempt to get the required chrome debugging profile name string.
   154       profileName = profileService.selectedProfile.name + CHROME_DEBUGGER_PROFILE_NAME;
   155       dumpn("Using chrome toolbox profile name: " + profileName);
   156     } catch (e) {
   157       // Requested profile string could not be retrieved.
   158       profileName = CHROME_DEBUGGER_PROFILE_NAME;
   159       let msg = "Querying the current profile failed. " + e.name + ": " + e.message;
   160       dumpn(msg);
   161       Cu.reportError(msg);
   162     }
   164     let profileObject;
   165     try {
   166       // Attempt to get the required chrome debugging profile toolkit object.
   167       profileObject = profileService.getProfileByName(profileName);
   168       dumpn("Using chrome toolbox profile object: " + profileObject);
   170       // The profile exists but the corresponding folder may have been deleted.
   171       var enumerator = Services.dirsvc.get("ProfD", Ci.nsIFile).parent.directoryEntries;
   172       while (enumerator.hasMoreElements()) {
   173         let profileDir = enumerator.getNext().QueryInterface(Ci.nsIFile);
   174         if (profileDir.leafName.contains(profileName)) {
   175           // Requested profile was found and the folder exists.
   176           this._dbgProfile = profileObject;
   177           return;
   178         }
   179       }
   180       // Requested profile was found but the folder was deleted. Cleanup needed.
   181       profileObject.remove(true);
   182       dumpn("The already existing chrome toolbox profile was invalid.");
   183     } catch (e) {
   184       // Requested profile object was not found.
   185       let msg = "Creating a profile failed. " + e.name + ": " + e.message;
   186       dumpn(msg);
   187       Cu.reportError(msg);
   188     }
   190     // Create a new chrome debugging profile.
   191     this._dbgProfile = profileService.createProfile(null, profileName);
   192     profileService.flush();
   194     dumpn("Finished creating the chrome toolbox user profile.");
   195     dumpn("Flushed profile service with: " + profileName);
   196   },
   198   /**
   199    * Creates and initializes the profile & process for the remote debugger.
   200    */
   201   _create: function() {
   202     dumpn("Initializing chrome debugging process.");
   203     let process = this._dbgProcess = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
   204     process.init(Services.dirsvc.get("XREExeF", Ci.nsIFile));
   206     let xulURI = DBG_XUL;
   208     if (this._options.addonID) {
   209       xulURI += "?addonID=" + this._options.addonID;
   210     }
   212     dumpn("Running chrome debugging process.");
   213     let args = ["-no-remote", "-foreground", "-P", this._dbgProfile.name, "-chrome", xulURI];
   215     process.runwAsync(args, args.length, { observe: () => this.close() });
   217     this._telemetry.toolOpened("jsbrowserdebugger");
   219     dumpn("Chrome toolbox is now running...");
   220     this.emit("run", this);
   221   },
   223   /**
   224    * Closes the remote debugging server and kills the toolbox process.
   225    */
   226   close: function() {
   227     if (this.closed) {
   228       return;
   229     }
   231     dumpn("Cleaning up the chrome debugging process.");
   232     Services.obs.removeObserver(this.close, "quit-application");
   234     if (this._dbgProcess.isRunning) {
   235       this._dbgProcess.kill();
   236     }
   238     this._telemetry.toolClosed("jsbrowserdebugger");
   239     if (this.debuggerServer) {
   240       this.debuggerServer.destroy();
   241     }
   243     dumpn("Chrome toolbox is now closed...");
   244     this.closed = true;
   245     this.emit("close", this);
   246     processes.delete(this);
   247   }
   248 };
   250 /**
   251  * Shortcuts for accessing various debugger preferences.
   252  */
   253 let Prefs = new ViewHelpers.Prefs("devtools.debugger", {
   254   chromeDebuggingHost: ["Char", "chrome-debugging-host"],
   255   chromeDebuggingPort: ["Int", "chrome-debugging-port"]
   256 });
   258 /**
   259  * Helper method for debugging.
   260  * @param string
   261  */
   262 function dumpn(str) {
   263   if (wantLogging) {
   264     dump("DBG-FRONTEND: " + str + "\n");
   265   }
   266 }
   268 let wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");
   270 Services.prefs.addObserver("devtools.debugger.log", {
   271   observe: (...args) => wantLogging = Services.prefs.getBoolPref(args.pop())
   272 }, false);

mercurial