/* 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";
var {
ActorRegistry,
} = require("resource://devtools/server/actors/utils/actor-registry.js"); var DevToolsUtils = require("resource://devtools/shared/DevToolsUtils.js"); var { dumpn } = DevToolsUtils;
/** * DevToolsServer is a singleton that has several responsibilities. It will * register the DevTools server actors that are relevant to the context. * It can also create other DevToolsServer, that will live in the same * environment as the debugged target (content page, worker...). * * For instance a regular Toolbox will be linked to DevToolsClient connected to * a DevToolsServer running in the same process as the Toolbox (main process). * But another DevToolsServer will be created in the same process as the page * targeted by the Toolbox. * * Despite being a singleton, the DevToolsServer still has a lifecycle and a * state. When a consumer needs to spawn a DevToolsServer, the init() method * should be called. Then you should either call registerAllActors or * registerActors to setup the server. * When the server is no longer needed, destroy() should be called. *
*/ var DevToolsServer = {
_listeners: [],
_initialized: false, // Map of global actor names to actor constructors.
globalActorFactories: {}, // Map of target-scoped actor names to actor constructors.
targetScopedActorFactories: {},
/** * The windowtype of the chrome window to use for actors that use the global * window (i.e the global style editor). Set this to your main window type, * for example "navigator:browser".
*/
chromeWindowType: "navigator:browser",
/** * Allow debugging chrome of (parent or child) processes.
*/
allowChromeProcess: false,
/** * Flag used to check if the server can be destroyed when all connections have been * removed. Firefox on Android runs a single shared DevToolsServer, and should not be * closed even if no client is connected.
*/
keepAlive: false,
/** * We run a special server in child process whose main actor is an instance * of WindowGlobalTargetActor, but that isn't a root actor. Instead there is no root * actor registered on DevToolsServer.
*/
get rootlessServer() { return !this.createRootActor;
},
/** * Initialize the devtools server.
*/
init() { if (this.initialized) { return;
}
if (!isWorker) { // Mochitests watch this observable in order to register the custom actor // highlighter-test-actor.js. // Services.obs is not available in workers. const subject = { wrappedJSObject: ActorRegistry };
Services.obs.notifyObservers(subject, "devtools-server-initialized");
}
},
get protocol() { return require("resource://devtools/shared/protocol.js");
},
hasConnectionForPrefix(prefix) { returnthis._connections && !!this._connections[prefix + "/"];
}, /** * Performs cleanup tasks before shutting down the devtools server. Such tasks * include clearing any actor constructors added at runtime. This method * should be called whenever a devtools server is no longer useful, to avoid * memory leaks. After this method returns, the devtools server must be * initialized again before use.
*/
destroy() { if (!this._initialized) { return;
} this._initialized = false;
for (const connection of Object.values(this._connections)) {
connection.close();
}
// Unregister all listeners this.off("connectionchange");
dumpn("DevTools server is shut down.");
},
/** * Raises an exception if the server has not been properly initialized.
*/
_checkInit() { if (!this._initialized) { thrownew Error("DevToolsServer has not been initialized.");
}
if (!this.rootlessServer && !this.createRootActor) { thrownew Error( "Use DevToolsServer.setRootActor() to add a root actor " + "implementation."
);
}
},
/** * Register different type of actors. Only register the one that are not already * registered. * * @param root boolean * Registers the root actor from webbrowser module, which is used to * connect to and fetch any other actor. * @param browser boolean * Registers all the parent process actors useful for debugging the * runtime itself, like preferences and addons actors. * @param target boolean * Registers all the target-scoped actors like console, script, etc. * for debugging a target context.
*/
registerActors({ root, browser, target }) { if (browser) {
ActorRegistry.addBrowserActors();
}
if (target) {
ActorRegistry.addTargetScopedActors();
}
},
/** * Register all possible actors for this DevToolsServer.
*/
registerAllActors() { this.registerActors({ root: true, browser: true, target: true });
},
get listeningSockets() { returnthis._listeners.length;
},
/** * Add a SocketListener instance to the server's set of active * SocketListeners. This is called by a SocketListener after it is opened.
*/
addSocketListener(listener) { if (!Services.prefs.getBoolPref("devtools.debugger.remote-enabled")) { thrownew Error("Can't add a SocketListener, remote debugging disabled");
} this._checkInit();
/** * Remove a SocketListener instance from the server's set of active * SocketListeners. This is called by a SocketListener after it is closed.
*/
removeSocketListener(listener) { // Remove connections that were accepted in the listener. for (const connID of Object.getOwnPropertyNames(this._connections)) { const connection = this._connections[connID]; // When calling connection.close on a previous element, // this may unregister some of the following other connections in `_connections` // and make them be null here. if (!connection) { continue;
} if (connection.isAcceptedBy(listener)) {
connection.close();
}
}
this._listeners = this._listeners.filter(l => l !== listener);
listener.off("accepted", this._onSocketListenerAccepted);
},
/** * Closes and forgets all previously opened listeners. * * @return boolean * Whether any listeners were actually closed.
*/
closeAllSocketListeners() { if (!this.listeningSockets) { returnfalse;
}
for (const listener of this._listeners) {
listener.close();
}
/** * Creates a new connection to the local debugger speaking over a fake * transport. This connection results in straightforward calls to the onPacket * handlers of each side. * * @param prefix string [optional] * If given, all actors in this connection will have names starting * with |prefix + '/'|. * @returns a client-side DebuggerTransport for communicating with * the newly-created connection.
*/
connectPipe(prefix) { this._checkInit();
const serverTransport = new LocalDebuggerTransport(); const clientTransport = new LocalDebuggerTransport(serverTransport);
serverTransport.other = clientTransport; const connection = this._onConnection(serverTransport, prefix);
// I'm putting this here because I trust you. // // There are times, when using a local connection, when you're going // to be tempted to just get direct access to the server. Resist that // temptation! If you succumb to that temptation, you will make the // fine developers that work on Fennec and Firefox OS sad. They're // professionals, they'll try to act like they understand, but deep // down you'll know that you hurt them. // // This reference allows you to give in to that temptation. There are // times this makes sense: tests, for example, and while porting a // previously local-only codebase to the remote protocol. // // But every time you use this, you will feel the shame of having // used a property that starts with a '_'.
clientTransport._serverConnection = connection;
return clientTransport;
},
/** * In a content child process, create a new connection that exchanges * nsIMessageSender messages with our parent process. * * @param prefix * The prefix we should use in our nsIMessageSender message names and * actor names. This connection will use messages named * "debug:<prefix>:packet", and all its actors will have names * beginning with "<prefix>/".
*/
connectToParent(prefix, scopeOrManager) { this._checkInit();
const transport = isWorker
? new WorkerThreadWorkerDebuggerTransport(scopeOrManager, prefix)
: new ChildDebuggerTransport(scopeOrManager, prefix);
/** * Check if the server is running in the child process.
*/
get isInChildProcess() { return (
Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT
);
},
/** * Create a new debugger connection for the given transport. Called after * connectPipe(), from connectToParent, or from an incoming socket * connection handler. * * If present, |forwardingPrefix| is a forwarding prefix that a parent * server is using to recognizes messages intended for this server. Ensure * that all our actors have names beginning with |forwardingPrefix + '/'|. * In particular, the root actor's name will be |forwardingPrefix + '/root'|.
*/
_onConnection(
transport,
forwardingPrefix,
noRootActor = false,
socketListener = null
) {
let connID; if (forwardingPrefix) {
connID = forwardingPrefix + "/";
} else { // Multiple servers can be started at the same time, and when that's the // case, they are loaded in separate devtools loaders. // So, use the current loader ID to prefix the connection ID and make it // unique.
connID = "server" + loader.id + ".conn" + this._nextConnID++ + ".";
}
// Notify the platform code that DevTools is running in the current process // when we are wiring the very first connection if (!this.hasConnection()) {
ChromeUtils.notifyDevToolsOpened();
}
// Create a root actor for the connection and send the hello packet. if (!noRootActor) {
conn.rootActor = this.createRootActor(conn); if (forwardingPrefix) {
conn.rootActor.actorID = forwardingPrefix + "/root";
} else {
conn.rootActor.actorID = "root";
}
conn.addActor(conn.rootActor);
transport.send(conn.rootActor.sayHello());
}
transport.ready();
/** * Remove the connection from the debugging server.
*/
_connectionClosed(connection) { deletethis._connections[connection.prefix]; this.emit("connectionchange", "closed", connection);
const hasConnection = this.hasConnection();
// Notify the platform code that we stopped running DevTools code in the current process if (!hasConnection) {
ChromeUtils.notifyDevToolsClosed();
}
// If keepAlive isn't explicitely set to true, destroy the server once its // last connection closes. Multiple JSWindowActor may use the same DevToolsServer // and in this case, let the server destroy itself once the last connection closes. // Otherwise we set keepAlive to true when starting a listening server, receiving // client connections. Typically when running server on phones, or on desktop // via `--start-debugger-server`. if (hasConnection || this.keepAlive) { return;
}
/** * Called when DevTools are unloaded to remove the contend process server startup script * for the list of scripts loaded for each new content process. Will also remove message * listeners from already loaded scripts.
*/
removeContentServerScript() {
Services.ppmm.removeDelayedProcessScript(
CONTENT_PROCESS_SERVER_STARTUP_SCRIPT
); try {
Services.ppmm.broadcastAsyncMessage("debug:close-content-server");
} catch (e) { // Nothing to do
}
},
/** * Searches all active connections for an actor matching an ID. * * ⚠ TO BE USED ONLY FROM SERVER CODE OR TESTING ONLY! ⚠` * * This is helpful for some tests which depend on reaching into the server to check some * properties of an actor, and it is also used by the actors related to the * DevTools WebExtensions API to be able to interact with the actors created for the * panels natively provided by the DevTools Toolbox.
*/
searchAllConnectionsForActor(actorID) { // NOTE: the actor IDs are generated with the following format: // // `server${loaderID}.conn${ConnectionID}${ActorPrefix}${ActorID}` // // as an optimization we can come up with a regexp to query only // the right connection via its id. for (const connID of Object.getOwnPropertyNames(this._connections)) { const actor = this._connections[connID].getActor(actorID); if (actor) { return actor;
}
} returnnull;
},
};
// Expose these to save callers the trouble of importing DebuggerSocket
DevToolsUtils.defineLazyGetter(DevToolsServer, "Authenticators", () => { return Authentication.Authenticators;
});
DevToolsUtils.defineLazyGetter(DevToolsServer, "AuthenticationResult", () => { return Authentication.AuthenticationResult;
});
EventEmitter.decorate(DevToolsServer);
exports.DevToolsServer = DevToolsServer;
¤ Dauer der Verarbeitung: 0.19 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.