Bug 1706094 - [devtools] Set watchedByDevTools browsingContextflag in the parent process. r=ochameau.

We're using frame-helper#createTargets to set the flag as we're already looping
over the browsing context we need to handle.
We keep a Map of watcher/observer so we can remove the observer when the targets
get destroyed.

For the browser toolbox top-level browsing context we keep setting the flag in
the browsing context target actor as it lives in the parent process, and we
don't have watcher support enabled by default, so frame-helper wouldn't be hit.
frame-helper is not used in the legacy browser toolbox, so we won't set the flag
on tabs when devtools.browsertoolbox.fission is false, but that's okay it's not
currently set anyway in this setup.

Tests are added with multiple cases to ensure the flag is set in different situations.

Differential Revision: https://phabricator.services.mozilla.com/D113628
This commit is contained in:
Nicolas Chevobbe 2021-05-05 08:04:24 +00:00
Родитель c23d24e129
Коммит 581f3fd2ca
6 изменённых файлов: 283 добавлений и 8 удалений

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

@ -34,3 +34,4 @@ prefs =
[browser_browser_toolbox_rtl.js]
[browser_browser_toolbox_ruleview_stylesheet.js]
[browser_browser_toolbox_shouldprocessupdates.js]
[browser_browser_toolbox_watchedByDevTools.js]

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

@ -0,0 +1,129 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Check that the "watchedByDevTools" flag is properly handled.
*/
const EXAMPLE_NET_URI =
"http://example.net/document-builder.sjs?html=<div id=net>net";
const EXAMPLE_COM_URI =
"https://example.com/document-builder.sjs?html=<div id=com>com";
const EXAMPLE_ORG_URI =
"https://example.org/document-builder.sjs?headers=Cross-Origin-Opener-Policy:same-origin&html=<div id=org>org</div>";
add_task(async function() {
const isMbtEnabled = Services.prefs.getBoolPref(
"devtools.browsertoolbox.fission",
false
);
const topWindow = Services.wm.getMostRecentWindow("navigator:browser");
is(
topWindow.browsingContext.watchedByDevTools,
false,
"watchedByDevTools isn't set on the parent process browsing context when DevTools aren't opened"
);
// Open 2 tabs that we can check the flag on
const tabNet = await addTab(EXAMPLE_NET_URI);
const tabCom = await addTab(EXAMPLE_COM_URI);
is(
tabNet.linkedBrowser.browsingContext.watchedByDevTools,
false,
"watchedByDevTools is not set on the .net tab"
);
is(
tabCom.linkedBrowser.browsingContext.watchedByDevTools,
false,
"watchedByDevTools is not set on the .com tab"
);
info("Open the BrowserToolbox so the parent process will be watched");
const ToolboxTask = await initBrowserToolboxTask();
is(
topWindow.browsingContext.watchedByDevTools,
true,
"watchedByDevTools is set when the browser toolbox is opened"
);
// Open a new tab when the browser toolbox is opened
const newTab = await addTab(EXAMPLE_COM_URI);
// Only check the flag value on tab's browsing contexts when the MultiProcess Browser Toolbox
// is enabled as the flag isn't set there in the Legacy Browser Toolbox
if (isMbtEnabled) {
is(
tabNet.linkedBrowser.browsingContext.watchedByDevTools,
true,
"watchedByDevTools is set on the .net tab browsing context after opening the browser toolbox"
);
is(
tabCom.linkedBrowser.browsingContext.watchedByDevTools,
true,
"watchedByDevTools is set on the .com tab browsing context after opening the browser toolbox"
);
info(
"Check that adding watchedByDevTools is set on a tab that was added when the browser toolbox was opened"
);
is(
newTab.linkedBrowser.browsingContext.watchedByDevTools,
true,
"watchedByDevTools is set on the newly opened tab"
);
info(
"Check that watchedByDevTools persist when navigating to a page that creates a new browsing context"
);
const previousBrowsingContextId = newTab.linkedBrowser.browsingContext.id;
const onBrowserLoaded = BrowserTestUtils.browserLoaded(
newTab.linkedBrowser,
false,
encodeURI(EXAMPLE_ORG_URI)
);
BrowserTestUtils.loadURI(newTab.linkedBrowser, EXAMPLE_ORG_URI);
await onBrowserLoaded;
isnot(
newTab.linkedBrowser.browsingContext.id,
previousBrowsingContextId,
"A new browsing context was created"
);
is(
newTab.linkedBrowser.browsingContext.watchedByDevTools,
true,
"watchedByDevTools is still set after navigating the tab to a page which forces a new browsing context"
);
}
info("Destroying browser toolbox");
await ToolboxTask.destroy();
is(
topWindow.browsingContext.watchedByDevTools,
false,
"watchedByDevTools was reset when the browser toolbox was closed"
);
is(
tabNet.linkedBrowser.browsingContext.watchedByDevTools,
false,
"watchedByDevTools was reset on the .net tab after closing the browser toolbox"
);
is(
tabCom.linkedBrowser.browsingContext.watchedByDevTools,
false,
"watchedByDevTools was reset on the .com tab after closing the browser toolbox"
);
is(
newTab.linkedBrowser.browsingContext.watchedByDevTools,
false,
"watchedByDevTools was reset on the tab opened while the browser toolbox was opened"
);
});

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

@ -154,6 +154,7 @@ run-if = e10s
[browser_toolbox_view_source_01.js]
[browser_toolbox_view_source_02.js]
[browser_toolbox_view_source_03.js]
[browser_toolbox_watchedByDevTools.js]
[browser_toolbox_window_reload_target.js]
[browser_toolbox_window_reload_target_force.js]
[browser_toolbox_window_shortcuts.js]

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

@ -0,0 +1,72 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Check that the "watchedByDevTools" flag is properly handled.
*/
const EXAMPLE_NET_URI =
"http://example.net/document-builder.sjs?html=<div id=net>net";
const EXAMPLE_COM_URI =
"https://example.com/document-builder.sjs?html=<div id=com>com";
const EXAMPLE_ORG_URI =
"https://example.org/document-builder.sjs?headers=Cross-Origin-Opener-Policy:same-origin&html=<div id=org>org</div>";
add_task(async function() {
const tab = await addTab(EXAMPLE_NET_URI);
is(
tab.linkedBrowser.browsingContext.watchedByDevTools,
false,
"watchedByDevTools isn't set when DevTools aren't opened"
);
info(
"Open a toolbox for the opened tab and check that watchedByDevTools is set"
);
await gDevTools.showToolboxForTab(tab, { toolId: "options" });
is(
tab.linkedBrowser.browsingContext.watchedByDevTools,
true,
"watchedByDevTools is set after opening a toolbox"
);
info(
"Check that watchedByDevTools persist when the tab navigates to a different origin"
);
await navigateTo(EXAMPLE_COM_URI);
is(
tab.linkedBrowser.browsingContext.watchedByDevTools,
true,
"watchedByDevTools is still set after navigating to a different origin"
);
info(
"Check that watchedByDevTools persist when navigating to a page that creates a new browsing context"
);
const previousBrowsingContextId = tab.linkedBrowser.browsingContext.id;
await navigateTo(EXAMPLE_ORG_URI);
isnot(
tab.linkedBrowser.browsingContext.id,
previousBrowsingContextId,
"A new browsing context was created"
);
is(
tab.linkedBrowser.browsingContext.watchedByDevTools,
true,
"watchedByDevTools is still set after navigating to a new browsing context"
);
info("Check that the flag is reset when the toolbox is closed");
await gDevTools.closeToolboxForTab(tab);
is(
tab.linkedBrowser.browsingContext.watchedByDevTools,
false,
"watchedByDevTools is reset after closing the toolbox"
);
});

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

@ -1674,9 +1674,14 @@ DebuggerProgressListener.prototype = {
// - reporting the contents of HTML loaded in the docshells,
// - or capturing stacks for the network monitor.
//
// This attribute may already have been toggled by a parent BrowsingContext.
// Typically the parent process or tab target. Both are top level BrowsingContext.
if (docShell.browsingContext.top == docShell.browsingContext) {
// This flag is also set in frame-helper but in the case of the browser toolbox, we
// don't have the watcher enabled by default yet, and as a result we need to set it
// here for the parent process browsing context.
// This should be removed as part of Bug 1709529.
if (
this._targetActor.typeName === "parentProcessTarget" &&
docShell.browsingContext.top == docShell.browsingContext
) {
docShell.browsingContext.watchedByDevTools = true;
}
},
@ -1711,11 +1716,12 @@ DebuggerProgressListener.prototype = {
this._knownWindowIDs.delete(getWindowID(win));
}
// We can only toggle this attribute on top level BrowsingContext,
// this will be propagated over the whole tree of BC.
// So we only need to set it from Parent Process Target
// and Tab Target. Tab's BrowsingContext are actually considered as top level BC.
if (docShell.browsingContext.top == docShell.browsingContext) {
// We only reset it for parent process target actor as the flag should be set in parent
// process, and thus is set elsewhere for other type of BrowsingContextActor.
if (
this._targetActor.typeName === "parentProcessTarget" &&
docShell.browsingContext.top == docShell.browsingContext
) {
docShell.browsingContext.watchedByDevTools = false;
}
},

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

@ -4,6 +4,7 @@
"use strict";
const Services = require("Services");
const {
WatcherRegistry,
} = require("devtools/server/actors/watcher/WatcherRegistry.jsm");
@ -16,6 +17,8 @@ const {
shouldNotifyWindowGlobal,
} = require("devtools/server/actors/watcher/target-helpers/utils.js");
const browsingContextAttachedObserverByWatcher = new Map();
/**
* Force creating targets for all existing BrowsingContext, that, for a given Watcher Actor.
*
@ -36,6 +39,13 @@ async function createTargets(watcher) {
"Existing WindowGlobal"
);
// We need to set the watchedByDevTools flag on all top-level browsing context. In the
// case of a content toolbox, this is done in the tab descriptor, but when we're in the
// browser toolbox, such descriptor is not created.
if (browsingContext.top === browsingContext) {
browsingContext.watchedByDevTools = true;
}
// Await for the query in order to try to resolve only *after* we received these
// already available targets.
const promise = browsingContext.currentWindowGlobal
@ -48,6 +58,46 @@ async function createTargets(watcher) {
});
promises.push(promise);
}
// If we have a browserElement, set the watchedByDevTools flag on its related browsing context
// TODO: We should also set the flag for the "parent process" browsing context when we're
// in the browser toolbox. This is blocked by Bug 1675763, and should be handled as part
// of Bug 1709529.
if (watcher.browserElement) {
// The `watchedByDevTools` enables gecko behavior tied to this flag, such as:
// - reporting the contents of HTML loaded in the docshells
// - capturing stacks for the network monitor.
watcher.browserElement.browsingContext.watchedByDevTools = true;
}
if (!browsingContextAttachedObserverByWatcher.has(watcher)) {
// We store the browserId here as watcher.browserElement.browserId can momentary be
// set to 0 when there's a navigation to a new browsing context.
const browserId = watcher.browserElement?.browserId;
const onBrowsingContextAttached = browsingContext => {
// We want to set watchedByDevTools on new top-level browsing contexts:
// - in the case of the BrowserToolbox/BrowserConsole, that would be the browsing
// contexts of all the tabs we want to handle.
// - for the regular toolbox, browsing context that are being created when navigating
// to a page that forces a new browsing context.
if (
browsingContext.top === browsingContext &&
(!watcher.browserElement || browserId === browsingContext.browserId)
) {
browsingContext.watchedByDevTools = true;
}
};
Services.obs.addObserver(
onBrowsingContextAttached,
"browsing-context-attached"
);
// We store the observer so we can retrieve it elsewhere (e.g. for removal in destroyTargets).
browsingContextAttachedObserverByWatcher.set(
watcher,
onBrowsingContextAttached
);
}
return Promise.all(promises);
}
@ -68,6 +118,10 @@ function destroyTargets(watcher) {
"Existing WindowGlobal"
);
if (browsingContext.top === browsingContext) {
browsingContext.watchedByDevTools = false;
}
browsingContext.currentWindowGlobal
.getActor("DevToolsFrame")
.destroyTarget({
@ -75,6 +129,18 @@ function destroyTargets(watcher) {
browserId: watcher.browserId,
});
}
if (watcher.browserElement) {
watcher.browserElement.browsingContext.watchedByDevTools = false;
}
if (browsingContextAttachedObserverByWatcher.has(watcher)) {
Services.obs.removeObserver(
browsingContextAttachedObserverByWatcher.get(watcher),
"browsing-context-attached"
);
browsingContextAttachedObserverByWatcher.delete(watcher);
}
}
/**