summaryrefslogtreecommitdiffstats
path: root/devtools/client/fronts/descriptors/process.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/fronts/descriptors/process.js')
-rw-r--r--devtools/client/fronts/descriptors/process.js142
1 files changed, 142 insertions, 0 deletions
diff --git a/devtools/client/fronts/descriptors/process.js b/devtools/client/fronts/descriptors/process.js
new file mode 100644
index 0000000000..6efc1bd4d7
--- /dev/null
+++ b/devtools/client/fronts/descriptors/process.js
@@ -0,0 +1,142 @@
+/* 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 {
+ processDescriptorSpec,
+} = require("resource://devtools/shared/specs/descriptors/process.js");
+const {
+ WindowGlobalTargetFront,
+} = require("resource://devtools/client/fronts/targets/window-global.js");
+const {
+ ContentProcessTargetFront,
+} = require("resource://devtools/client/fronts/targets/content-process.js");
+const {
+ FrontClassWithSpec,
+ registerFront,
+} = require("resource://devtools/shared/protocol.js");
+const {
+ DescriptorMixin,
+} = require("resource://devtools/client/fronts/descriptors/descriptor-mixin.js");
+const DESCRIPTOR_TYPES = require("resource://devtools/client/fronts/descriptors/descriptor-types.js");
+
+class ProcessDescriptorFront extends DescriptorMixin(
+ FrontClassWithSpec(processDescriptorSpec)
+) {
+ constructor(client, targetFront, parentFront) {
+ super(client, targetFront, parentFront);
+ this._isParent = false;
+ this._processTargetFront = null;
+ this._targetFrontPromise = null;
+ }
+
+ descriptorType = DESCRIPTOR_TYPES.PROCESS;
+
+ form(json) {
+ this.id = json.id;
+ this._isParent = json.isParent;
+ this._isWindowlessParent = json.isWindowlessParent;
+ this.traits = json.traits || {};
+ }
+
+ async _createProcessTargetFront(form) {
+ let front = null;
+ // the request to getTarget may return a ContentProcessTargetActor or a
+ // ParentProcessTargetActor. In most cases getProcess(0) will return the
+ // main process target actor, which is a ParentProcessTargetActor, but
+ // not in xpcshell, which uses a ContentProcessTargetActor. So select
+ // the right front based on the actor ID.
+ if (form.actor.includes("parentProcessTarget")) {
+ // ParentProcessTargetActor doesn't have a specific front, instead it uses
+ // WindowGlobalTargetFront on the client side.
+ front = new WindowGlobalTargetFront(this._client, null, this);
+ } else {
+ front = new ContentProcessTargetFront(this._client, null, this);
+ }
+ // As these fronts aren't instantiated by protocol.js, we have to set their actor ID
+ // manually like that:
+ front.actorID = form.actor;
+ front.form(form);
+
+ // @backward-compat { version 84 } Older server don't send the processID in the form
+ if (!front.processID) {
+ front.processID = this.id;
+ }
+
+ this.manage(front);
+ return front;
+ }
+
+ /**
+ * This flag should be true for parent process descriptors of a regular
+ * browser instance, where you can expect the target to be associated with a
+ * window global.
+ *
+ * This will typically be true for the descriptor used by the Browser Toolbox
+ * or the Browser Console opened against a regular Firefox instance.
+ *
+ * On the contrary this will be false for parent process descriptors created
+ * for xpcshell debugging or for background task debugging.
+ */
+ get isBrowserProcessDescriptor() {
+ return this._isParent && !this._isWindowlessParent;
+ }
+
+ get isParentProcessDescriptor() {
+ return this._isParent;
+ }
+
+ get isProcessDescriptor() {
+ return true;
+ }
+
+ getCachedTarget() {
+ return this._processTargetFront;
+ }
+
+ async getTarget() {
+ // Only return the cached Target if it is still alive.
+ if (this._processTargetFront && !this._processTargetFront.isDestroyed()) {
+ return this._processTargetFront;
+ }
+ // Otherwise, ensure that we don't try to spawn more than one Target by
+ // returning the pending promise
+ if (this._targetFrontPromise) {
+ return this._targetFrontPromise;
+ }
+ this._targetFrontPromise = (async () => {
+ let targetFront = null;
+ try {
+ const targetForm = await super.getTarget();
+ targetFront = await this._createProcessTargetFront(targetForm);
+ } catch (e) {
+ // This is likely to happen if we get a lot of events which drop previous
+ // processes.
+ console.log(
+ `Request to connect to ProcessDescriptor "${this.id}" failed: ${e}`
+ );
+ }
+ // Save the reference to the target only after the call to attach
+ // so that getTarget always returns the attached target in case of concurrent calls
+ this._processTargetFront = targetFront;
+ // clear the promise if we are finished so that we can re-connect if
+ // necessary
+ this._targetFrontPromise = null;
+ return targetFront;
+ })();
+ return this._targetFrontPromise;
+ }
+
+ destroy() {
+ if (this._processTargetFront) {
+ this._processTargetFront.destroy();
+ this._processTargetFront = null;
+ }
+ this._targetFrontPromise = null;
+ super.destroy();
+ }
+}
+
+exports.ProcessDescriptorFront = ProcessDescriptorFront;
+registerFront(ProcessDescriptorFront);