bug 1566450 - Implement a metaclass for content processes r=ochameau,jdescottes

WIP for metaclass concept

The best place to start is the test, it outlines what the API looks like.

Differential Revision: https://phabricator.services.mozilla.com/D37253

--HG--
extra : moz-landing-system : lando
This commit is contained in:
yulia 2019-07-29 13:19:49 +00:00
Родитель 627b67599a
Коммит dc867ee1d5
10 изменённых файлов: 262 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,10 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
DevToolsModules(
'process.js',
)

Просмотреть файл

@ -0,0 +1,111 @@
/* 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 Services = require("Services");
const { DebuggerServer } = require("devtools/server/main");
const { Cc, Ci } = require("chrome");
const { ActorClassWithSpec, Actor } = require("devtools/shared/protocol");
const {
processDescriptorSpec,
} = require("devtools/shared/specs/descriptors/process");
loader.lazyRequireGetter(
this,
"ContentProcessTargetActor",
"devtools/server/actors/targets/content-process",
true
);
loader.lazyRequireGetter(
this,
"ParentProcessTargetActor",
"devtools/server/actors/targets/parent-process",
true
);
const ProcessDescriptorActor = ActorClassWithSpec(processDescriptorSpec, {
initialize(connection, options = {}) {
if ("id" in options && typeof options.id != "number") {
throw Error("process connect requires a valid `id` attribute.");
}
Actor.prototype.initialize.call(this, connection);
this.id = options.id;
this.isParent = options.parent;
this.destroy = this.destroy.bind(this);
},
_parentProcessConnect() {
const env = Cc["@mozilla.org/process/environment;1"].getService(
Ci.nsIEnvironment
);
const isXpcshell = env.exists("XPCSHELL_TEST_PROFILE_DIR");
let targetActor = null;
if (isXpcshell) {
// Check if we are running on xpcshell.
// When running on xpcshell, there is no valid browsing context to attach to
// and so ParentProcessTargetActor doesn't make sense as it inherits from
// BrowsingContextTargetActor. So instead use ContentProcessTargetActor, which
// matches xpcshell needs.
targetActor = new ContentProcessTargetActor(this.conn);
} else {
// Create the target actor for the parent process, which is in the same process
// as this target. Because we are in the same process, we have a true actor that
// should be managed by the ProcessDescriptorActor.
targetActor = new ParentProcessTargetActor(this.conn);
}
this.manage(targetActor);
// to be consistent with the return value of the _childProcessConnect, we are returning
// the form here. This might be memoized in the future
return targetActor.form();
},
/**
* Connect to a remote process actor, always a ContentProcess target.
*/
async _childProcessConnect() {
const { id } = this;
const mm = Services.ppmm.getChildAt(id);
if (!mm) {
return {
error: "noProcess",
message: "There is no process with id '" + id + "'.",
};
}
const childTargetForm = await DebuggerServer.connectToContentProcess(
this.conn,
mm,
this.destroy
);
return childTargetForm;
},
/**
* Connect the a process actor.
*/
async getTarget() {
if (!DebuggerServer.allowChromeProcess) {
return {
error: "forbidden",
message: "You are not allowed to debug processes.",
};
}
if (this.isParent) {
return this._parentProcessConnect();
}
// This is a remote process we are connecting to
return this._childProcessConnect();
},
form() {
return {
actor: this.actorID,
id: this.id,
isParent: this.isParent,
};
},
});
exports.ProcessDescriptorActor = ProcessDescriptorActor;

Просмотреть файл

@ -7,6 +7,7 @@
DIRS += [
'accessibility',
'addon',
'descriptors',
'emulation',
'highlighters',
'inspector',

Просмотреть файл

@ -0,0 +1,10 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
DevToolsModules(
'process.js',
)

Просмотреть файл

@ -0,0 +1,94 @@
/* 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("devtools/shared/specs/descriptors/process");
const {
BrowsingContextTargetFront,
} = require("devtools/shared/fronts/targets/browsing-context");
const {
ContentProcessTargetFront,
} = require("devtools/shared/fronts/targets/content-process");
const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
class ProcessDescriptorFront extends FrontClassWithSpec(processDescriptorSpec) {
constructor(client) {
super(client);
this.isParent = false;
this._processTargetFront = null;
this._targetFrontPromise = null;
this._client = client;
}
form(json) {
this.id = json.id;
this.isParent = json.isParent;
}
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
// BrowsingContextTargetFront on the client side.
front = new BrowsingContextTargetFront(this._client);
} else {
front = new ContentProcessTargetFront(this._client);
}
// 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);
this.manage(front);
return front;
}
async getTarget() {
if (this._processTargetFront && this._processTargetFront.actorID) {
return this._processTargetFront;
}
if (this._targetFrontPromise) {
return this._targetFrontPromise;
}
this._targetFrontPromise = (async () => {
try {
const targetForm = await super.getTarget();
this._processTargetFront = await this._createProcessTargetFront(
targetForm
);
await this._processTargetFront.attach();
// clear the promise if we are finished so that we can re-connect if
// necessary
this._targetFrontPromise = null;
return this._processTargetFront;
} 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}`
);
return null;
}
})();
return this._targetFrontPromise;
}
destroy() {
this._processTargetFront = null;
this._targetFrontPromise = null;
super.destroy();
}
}
exports.ProcessDescriptorFront = ProcessDescriptorFront;
registerFront(ProcessDescriptorFront);

Просмотреть файл

@ -6,6 +6,7 @@
DIRS += [
'addon',
'descriptors',
'inspector',
'targets',
'worker',

Просмотреть файл

@ -0,0 +1,10 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
DevToolsModules(
'process.js',
)

Просмотреть файл

@ -0,0 +1,19 @@
/* 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 { generateActorSpec, RetVal } = require("devtools/shared/protocol");
const processDescriptorSpec = generateActorSpec({
typeName: "processDescriptor",
methods: {
getTarget: {
request: {},
response: { process: RetVal("json") },
},
},
});
exports.processDescriptorSpec = processDescriptorSpec;

Просмотреть файл

@ -57,6 +57,11 @@ const Types = (exports.__TypesForTests = [
spec: "devtools/shared/specs/css-properties",
front: "devtools/shared/fronts/css-properties",
},
{
types: ["processDescriptor"],
spec: "devtools/shared/specs/descriptors/process",
front: "devtools/shared/fronts/descriptors/process",
},
{
types: ["device"],
spec: "devtools/shared/specs/device",

Просмотреть файл

@ -6,6 +6,7 @@
DIRS += [
'addon',
'descriptors',
'targets',
'worker',
]