Bug 1492265 - Use a content process target actor for xpcshell debugging. r=jdescottes
authorAlexandre Poirot <poirot.alex@gmail.com>
Tue, 09 Oct 2018 09:31:08 +0000
changeset 495883 92eadc28f0339980235a752d57989febbe2cee90
parent 495882 a2fc465a0dd88db35a108be38898c7637d935efe
child 495884 3135daac034f319384a2515a1969fa0f3a4de1d4
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdescottes
bugs1492265
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1492265 - Use a content process target actor for xpcshell debugging. r=jdescottes MozReview-Commit-ID: J9XTgC0EBPG Depends on D7415 Differential Revision: https://phabricator.services.mozilla.com/D7416
devtools/client/framework/target.js
devtools/server/actors/root.js
devtools/server/actors/targets/content-process.js
devtools/server/tests/unit/test_promises_actor_attach.js
devtools/server/tests/unit/test_promises_actor_list_promises.js
devtools/server/tests/unit/test_promises_actor_onnewpromise.js
devtools/server/tests/unit/test_promises_actor_onpromisesettled.js
devtools/server/tests/unit/test_promises_client_getdependentpromises.js
devtools/server/tests/unit/test_promises_object_creationtimestamp.js
devtools/server/tests/unit/test_promises_object_timetosettle-01.js
devtools/server/tests/unit/test_promises_object_timetosettle-02.js
devtools/server/tests/unit/test_xpcshell_debugging.js
--- a/devtools/client/framework/target.js
+++ b/devtools/client/framework/target.js
@@ -224,18 +224,20 @@ function TabTarget({ form, client, chrom
   // target actor that doesn't have any valid browsing context.
   // (Once FF63 is no longer supported, we can remove the `else` branch and only look
   // for the traits)
   if (this._form.traits && ("isBrowsingContext" in this._form.traits)) {
     this._isBrowsingContext = this._form.traits.isBrowsingContext;
   } else {
     // browser content toolbox's form will be of the form:
     //   server0.conn0.content-process0/contentProcessTarget7
+    // while xpcshell debugging will be:
+    //   server1.conn0.contentProcessTarget7
     const isContentProcessTarget =
-      this._form.actor.match(/conn\d+\.content-process\d+\/contentProcessTarget\d+/);
+      this._form.actor.match(/conn\d+\.(content-process\d+\/)?contentProcessTarget\d+/);
     this._isBrowsingContext = !this.isLegacyAddon && !isContentProcessTarget;
   }
 
   // Cache of already created targed-scoped fronts
   // [typeName:string => Front instance]
   this.fronts = new Map();
   // Temporary fix for bug #1493131 - inspector has a different life cycle
   // than most other fronts because it is closely related to the toolbox.
--- a/devtools/server/actors/root.js
+++ b/devtools/server/actors/root.js
@@ -9,16 +9,20 @@
 const { Cu } = require("chrome");
 const Services = require("Services");
 const { Pool } = require("devtools/shared/protocol");
 const { LazyPool, createExtraActors } = require("devtools/shared/protocol/lazy-pool");
 const { DebuggerServer } = require("devtools/server/main");
 
 loader.lazyRequireGetter(this, "ChromeWindowTargetActor",
   "devtools/server/actors/targets/chrome-window", true);
+loader.lazyRequireGetter(this, "ContentProcessTargetActor",
+  "devtools/server/actors/targets/content-process", true);
+loader.lazyRequireGetter(this, "ParentProcessTargetActor",
+  "devtools/server/actors/targets/parent-process", true);
 
 /* Root actor for the remote debugging protocol. */
 
 /**
  * Create a remote debugging protocol root actor.
  *
  * @param connection
  *     The DebuggerServerConnection whose root actor we are constructing.
@@ -516,26 +520,40 @@ RootActor.prototype = {
     }
     if (("id" in request) && typeof (request.id) != "number") {
       return { error: "wrongParameter",
                message: "getProcess requires a valid `id` attribute." };
     }
     // If the request doesn't contains id parameter or id is 0
     // (id == 0, based on onListProcesses implementation)
     if ((!("id" in request)) || request.id === 0) {
-      if (this._parentProcessTargetActor && (!this._parentProcessTargetActor.docShell ||
-          this._parentProcessTargetActor.docShell.isBeingDestroyed)) {
+      // Check if we are running on xpcshell. hiddenDOMWindow is going to throw on it.
+      // 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.
+      let isXpcshell = true;
+      try {
+        isXpcshell = !Services.wm.getMostRecentWindow(null) &&
+                     !Services.appShell.hiddenDOMWindow;
+      } catch (e) {}
+
+      if (!isXpcshell && this._parentProcessTargetActor &&
+          (!this._parentProcessTargetActor.docShell ||
+            this._parentProcessTargetActor.docShell.isBeingDestroyed)) {
         this._parentProcessTargetActor.destroy();
         this._parentProcessTargetActor = null;
       }
       if (!this._parentProcessTargetActor) {
-        // Create a ParentProcessTargetActor for the parent process
-        const { ParentProcessTargetActor } =
-          require("devtools/server/actors/targets/parent-process");
-        this._parentProcessTargetActor = new ParentProcessTargetActor(this.conn);
+        // Create the target actor for the parent process
+        if (isXpcshell) {
+          this._parentProcessTargetActor = new ContentProcessTargetActor(this.conn);
+        } else {
+          this._parentProcessTargetActor = new ParentProcessTargetActor(this.conn);
+        }
         this._globalActorPool.manage(this._parentProcessTargetActor);
       }
 
       return { form: this._parentProcessTargetActor.form() };
     }
 
     const { id } = request;
     const mm = Services.ppmm.getChildAt(id);
--- a/devtools/server/actors/targets/content-process.js
+++ b/devtools/server/actors/targets/content-process.js
@@ -19,16 +19,17 @@ const { WebConsoleActor } = require("dev
 const makeDebugger = require("devtools/server/actors/utils/make-debugger");
 const { ActorPool } = require("devtools/server/actors/common");
 const { Pool } = require("devtools/shared/protocol");
 const { assert } = require("devtools/shared/DevToolsUtils");
 const { TabSources } = require("devtools/server/actors/utils/TabSources");
 
 loader.lazyRequireGetter(this, "WorkerTargetActorList", "devtools/server/actors/worker/worker-list", true);
 loader.lazyRequireGetter(this, "MemoryActor", "devtools/server/actors/memory", true);
+loader.lazyRequireGetter(this, "PromisesActor", "devtools/server/actors/promises", true);
 
 function ContentProcessTargetActor(connection) {
   this.conn = connection;
   this._contextPool = new ActorPool(this.conn);
   this.conn.addActorPool(this._contextPool);
   this.threadActor = null;
 
   // Use a see-everything debugger
@@ -96,23 +97,31 @@ ContentProcessTargetActor.prototype = {
     if (!this.threadActor) {
       this.threadActor = new ChromeDebuggerActor(this.conn, this);
       this._contextPool.addActor(this.threadActor);
     }
     if (!this.memoryActor) {
       this.memoryActor = new MemoryActor(this.conn, this);
       this._contextPool.addActor(this.memoryActor);
     }
+    // Promises actor is being tested by xpcshell test, which uses the content process
+    // target actor. But this actor isn't being used outside of tests yet.
+    if (!this._promisesActor) {
+      this._promisesActor = new PromisesActor(this.conn, this);
+      this._contextPool.addActor(this._promisesActor);
+    }
+
     return {
       actor: this.actorID,
       name: "Content process",
 
       consoleActor: this._consoleActor.actorID,
       chromeDebugger: this.threadActor.actorID,
       memoryActor: this.memoryActor.actorID,
+      promisesActor: this._promisesActor.actorID,
 
       traits: {
         highlightable: false,
         networkMonitor: false,
       },
     };
   },
 
--- a/devtools/server/tests/unit/test_promises_actor_attach.js
+++ b/devtools/server/tests/unit/test_promises_actor_attach.js
@@ -10,24 +10,22 @@
 
 const { PromisesFront } = require("devtools/shared/fronts/promises");
 
 add_task(async function() {
   const client = await startTestDebuggerServer("promises-actor-test");
   const parentProcessActors = await getParentProcessActors(client);
 
   // We have to attach the chrome target actor before playing with the PromiseActor
-  await attachTarget(client, parentProcessActors);
   await testAttach(client, parentProcessActors);
 
   const response = await listTabs(client);
   const targetTab = findTab(response.tabs, "promises-actor-test");
   ok(targetTab, "Found our target tab.");
 
-  await attachTarget(client, targetTab);
   await testAttach(client, targetTab);
 
   await close(client);
 });
 
 async function testAttach(client, parent) {
   const promises = PromisesFront(client, parent);
 
--- a/devtools/server/tests/unit/test_promises_actor_list_promises.js
+++ b/devtools/server/tests/unit/test_promises_actor_list_promises.js
@@ -11,17 +11,16 @@
 const { PromisesFront } = require("devtools/shared/fronts/promises");
 const SECRET = "MyLittleSecret";
 
 add_task(async function() {
   const client = await startTestDebuggerServer("promises-actor-test");
   const parentProcessActors = await getParentProcessActors(client);
 
   // We have to attach the chrome target actor before playing with the PromiseActor
-  await attachTarget(client, parentProcessActors);
   await testListPromises(client, parentProcessActors, v =>
     new Promise(resolve => resolve(v)));
 
   const response = await listTabs(client);
   const targetTab = findTab(response.tabs, "promises-actor-test");
   ok(targetTab, "Found our target tab.");
 
   await testListPromises(client, targetTab, v => {
--- a/devtools/server/tests/unit/test_promises_actor_onnewpromise.js
+++ b/devtools/server/tests/unit/test_promises_actor_onnewpromise.js
@@ -14,17 +14,16 @@ var EventEmitter = require("devtools/sha
 
 add_task(async function() {
   const client = await startTestDebuggerServer("promises-actor-test");
   const parentProcessActors = await getParentProcessActors(client);
 
   ok(Promise.toString().includes("native code"), "Expect native DOM Promise");
 
   // We have to attach the chrome target actor before playing with the PromiseActor
-  await attachTarget(client, parentProcessActors);
   await testNewPromisesEvent(client, parentProcessActors,
     v => new Promise(resolve => resolve(v)));
 
   const response = await listTabs(client);
   const targetTab = findTab(response.tabs, "promises-actor-test");
   ok(targetTab, "Found our target tab.");
 
   await testNewPromisesEvent(client, targetTab, v => {
--- a/devtools/server/tests/unit/test_promises_actor_onpromisesettled.js
+++ b/devtools/server/tests/unit/test_promises_actor_onpromisesettled.js
@@ -16,17 +16,16 @@ var EventEmitter = require("devtools/sha
 
 add_task(async function() {
   const client = await startTestDebuggerServer("promises-actor-test");
   const parentProcessActors = await getParentProcessActors(client);
 
   ok(Promise.toString().includes("native code"), "Expect native DOM Promise");
 
   // We have to attach the chrome target actor before playing with the PromiseActor
-  await attachTarget(client, parentProcessActors);
   await testPromisesSettled(client, parentProcessActors,
     v => new Promise(resolve => resolve(v)),
     v => new Promise((resolve, reject) => reject(v)));
 
   const response = await listTabs(client);
   const targetTab = findTab(response.tabs, "promises-actor-test");
   ok(targetTab, "Found our target tab.");
 
--- a/devtools/server/tests/unit/test_promises_client_getdependentpromises.js
+++ b/devtools/server/tests/unit/test_promises_client_getdependentpromises.js
@@ -9,17 +9,16 @@
 
 const { PromisesFront } = require("devtools/shared/fronts/promises");
 
 var EventEmitter = require("devtools/shared/event-emitter");
 
 add_task(async function() {
   const client = await startTestDebuggerServer("test-promises-dependentpromises");
   const parentProcessActors = await getParentProcessActors(client);
-  await attachTarget(client, parentProcessActors);
 
   ok(Promise.toString().includes("native code"), "Expect native DOM Promise.");
 
   await testGetDependentPromises(client, parentProcessActors, () => {
     const p = new Promise(() => {});
     p.name = "p";
     const q = p.then();
     q.name = "q";
@@ -27,17 +26,16 @@ add_task(async function() {
     r.name = "r";
 
     return p;
   });
 
   const response = await listTabs(client);
   const targetTab = findTab(response.tabs, "test-promises-dependentpromises");
   ok(targetTab, "Found our target tab.");
-  await attachTarget(client, targetTab);
 
   await testGetDependentPromises(client, targetTab, () => {
     const debuggee =
       DebuggerServer.getTestGlobal("test-promises-dependentpromises");
 
     const p = new debuggee.Promise(() => {});
     p.name = "p";
     const q = p.then();
--- a/devtools/server/tests/unit/test_promises_object_creationtimestamp.js
+++ b/devtools/server/tests/unit/test_promises_object_creationtimestamp.js
@@ -23,17 +23,16 @@ add_task(async function() {
   });
 
   const client = await startTestDebuggerServer("promises-object-test");
   const parentProcessActors = await getParentProcessActors(client);
 
   ok(Promise.toString().includes("native code"), "Expect native DOM Promise.");
 
   // We have to attach the chrome target actor before playing with the PromiseActor
-  await attachTarget(client, parentProcessActors);
   await testPromiseCreationTimestamp(client, parentProcessActors, v => {
     return new Promise(resolve => resolve(v));
   });
 
   const response = await listTabs(client);
   const targetTab = findTab(response.tabs, "promises-object-test");
   ok(targetTab, "Found our target tab.");
 
--- a/devtools/server/tests/unit/test_promises_object_timetosettle-01.js
+++ b/devtools/server/tests/unit/test_promises_object_timetosettle-01.js
@@ -14,17 +14,16 @@ var EventEmitter = require("devtools/sha
 
 add_task(async function() {
   const client = await startTestDebuggerServer("test-promises-timetosettle");
   const parentProcessActors = await getParentProcessActors(client);
 
   ok(Promise.toString().includes("native code"), "Expect native DOM Promise.");
 
   // We have to attach the chrome target actor before playing with the PromiseActor
-  await attachTarget(client, parentProcessActors);
   await testGetTimeToSettle(client, parentProcessActors, () => {
     const p = new Promise(() => {});
     p.name = "p";
     const q = p.then();
     q.name = "q";
 
     return p;
   });
--- a/devtools/server/tests/unit/test_promises_object_timetosettle-02.js
+++ b/devtools/server/tests/unit/test_promises_object_timetosettle-02.js
@@ -11,29 +11,26 @@
 const { PromisesFront } = require("devtools/shared/fronts/promises");
 const { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm", {});
 
 var EventEmitter = require("devtools/shared/event-emitter");
 
 add_task(async function() {
   const client = await startTestDebuggerServer("test-promises-timetosettle");
   const parentProcessActors = await getParentProcessActors(client);
-  await attachTarget(client, parentProcessActors);
 
   ok(Promise.toString().includes("native code"), "Expect native DOM Promise.");
 
   // We have to attach the chrome target actor before playing with the PromiseActor
-  await attachTarget(client, parentProcessActors);
   await testGetTimeToSettle(client, parentProcessActors,
     v => new Promise(resolve => setTimeout(() => resolve(v), 100)));
 
   const response = await listTabs(client);
   const targetTab = findTab(response.tabs, "test-promises-timetosettle");
   ok(targetTab, "Found our target tab.");
-  await attachTarget(client, targetTab);
 
   await testGetTimeToSettle(client, targetTab, v => {
     const debuggee =
       DebuggerServer.getTestGlobal("test-promises-timetosettle");
     return new debuggee.Promise(resolve => setTimeout(() => resolve(v), 100));
   });
 
   await close(client);
--- a/devtools/server/tests/unit/test_xpcshell_debugging.js
+++ b/devtools/server/tests/unit/test_xpcshell_debugging.js
@@ -23,19 +23,18 @@ add_task(async function() {
   // Ensure that global actors are available. Just test the device actor.
   const deviceFront = await client.mainRoot.getFront("device");
   const desc = await deviceFront.getDescription();
   equal(desc.geckobuildid, Services.appinfo.platformBuildID, "device actor works");
 
   // Even though we have no tabs, getProcess gives us the chromeDebugger.
   const response = await client.getProcess();
 
-  const actor = response.form.actor;
-  const [, tabClient] = await client.attachTarget(actor);
-  const [, threadClient] = await tabClient.attachThread(null);
+  const { chromeDebugger } = response.form;
+  const [, threadClient] = await client.attachThread(chromeDebugger);
   const onResumed = new Promise(resolve => {
     threadClient.addOneTimeListener("paused", (event, packet) => {
       equal(packet.why.type, "breakpoint",
           "yay - hit the breakpoint at the first line in our script");
       // Resume again - next stop should be our "debugger" statement.
       threadClient.addOneTimeListener("paused", (event, packet) => {
         equal(packet.why.type, "debuggerStatement",
               "yay - hit the 'debugger' statement in our script");