зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1664214 - In about:processes, only display root subframes;r=florian
To decrease visual clutter, we stop displaying frames that are purely in-process subframes of the tab. Differential Revision: https://phabricator.services.mozilla.com/D89878
This commit is contained in:
Родитель
7fce8717c1
Коммит
ff4e70cada
|
@ -4444,6 +4444,8 @@ pref("dom.clients.openwindow_favors_same_process", true);
|
|||
pref("toolkit.aboutPerformance.showInternals", true);
|
||||
#endif
|
||||
|
||||
// If `true`, about:processes shows in-process subframes.
|
||||
pref("toolkit.aboutProcesses.showAllSubframes", false);
|
||||
// If `true`, about:processes shows thread information.
|
||||
pref("toolkit.aboutProcesses.showThreads", false);
|
||||
|
||||
|
|
|
@ -32,6 +32,9 @@ const { WebExtensionPolicy } = Cu.getGlobalForObject(Services);
|
|||
const SHOW_THREADS = Services.prefs.getBoolPref(
|
||||
"toolkit.aboutProcesses.showThreads"
|
||||
);
|
||||
const SHOW_ALL_SUBFRAMES = Services.prefs.getBoolPref(
|
||||
"toolkit.aboutProcesses.showAllSubframes"
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns a Promise that's resolved after the next turn of the event loop.
|
||||
|
@ -993,8 +996,10 @@ var Control = {
|
|||
|
||||
let winRow;
|
||||
for (let win of process.windows) {
|
||||
winRow = View.appendDOMWindowRow(win, process);
|
||||
winRow.win = win;
|
||||
if (SHOW_ALL_SUBFRAMES || win.tab || win.isProcessRoot) {
|
||||
winRow = View.appendDOMWindowRow(win, process);
|
||||
winRow.win = win;
|
||||
}
|
||||
}
|
||||
|
||||
if (SHOW_THREADS) {
|
||||
|
|
|
@ -265,201 +265,242 @@ function extractProcessDetails(row) {
|
|||
add_task(async function testAboutProcesses() {
|
||||
info("Setting up about:processes");
|
||||
|
||||
// Test twice, once without `showThreads`, once with it.
|
||||
for (let showThreads of [false, true]) {
|
||||
// Test twice, once without `showAllSubframes`, once with it.
|
||||
for (let showAllFrames of [false, true]) {
|
||||
Services.prefs.setBoolPref(
|
||||
"toolkit.aboutProcesses.showThreads",
|
||||
showThreads
|
||||
"toolkit.aboutProcesses.showAllSubframes",
|
||||
showAllFrames
|
||||
);
|
||||
// The tab we're testing.
|
||||
let tabAboutProcesses = (gBrowser.selectedTab = BrowserTestUtils.addTab(
|
||||
gBrowser,
|
||||
"about:processes"
|
||||
));
|
||||
await BrowserTestUtils.browserLoaded(tabAboutProcesses.linkedBrowser);
|
||||
// Test twice, once without `showThreads`, once with it.
|
||||
for (let showThreads of [false, true]) {
|
||||
Services.prefs.setBoolPref(
|
||||
"toolkit.aboutProcesses.showThreads",
|
||||
showThreads
|
||||
);
|
||||
// The tab we're testing.
|
||||
let tabAboutProcesses = (gBrowser.selectedTab = BrowserTestUtils.addTab(
|
||||
gBrowser,
|
||||
"about:processes"
|
||||
));
|
||||
await BrowserTestUtils.browserLoaded(tabAboutProcesses.linkedBrowser);
|
||||
|
||||
info("Setting up example.com");
|
||||
// Another tab that we'll pretend is hung.
|
||||
let tabHung = BrowserTestUtils.addTab(gBrowser, "http://example.com");
|
||||
await BrowserTestUtils.browserLoaded(tabHung.linkedBrowser);
|
||||
|
||||
info("Setting up fake process hang detector");
|
||||
let hungChildID = tabHung.linkedBrowser.frameLoader.childID;
|
||||
|
||||
let doc = tabAboutProcesses.linkedBrowser.contentDocument;
|
||||
let tbody = doc.getElementById("process-tbody");
|
||||
|
||||
// Keep informing about:processes that `tabHung` is hung.
|
||||
// Note: this is a background task, do not `await` it.
|
||||
let fakeProcessHangMonitor = async function() {
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
if (!tabHung.linkedBrowser) {
|
||||
// Let's stop spamming as soon as we can.
|
||||
return;
|
||||
}
|
||||
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
Services.obs.notifyObservers(
|
||||
{
|
||||
childID: hungChildID,
|
||||
hangType: Ci.nsIHangReport.PLUGIN_HANG,
|
||||
pluginName: "Fake plug-in",
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIHangReport"]),
|
||||
},
|
||||
"process-hang-report"
|
||||
);
|
||||
}
|
||||
};
|
||||
fakeProcessHangMonitor();
|
||||
|
||||
info("Waiting for the first update of about:processes");
|
||||
// Wait until the table has first been populated.
|
||||
await TestUtils.waitForCondition(() => tbody.childElementCount);
|
||||
|
||||
info("Waiting for the second update of about:processes");
|
||||
// And wait for another update using a mutation observer, to give our newly created test tab some time
|
||||
// to burn some CPU.
|
||||
await new Promise(resolve => {
|
||||
let observer = new doc.ownerGlobal.MutationObserver(() => {
|
||||
observer.disconnect();
|
||||
resolve();
|
||||
info("Setting up example.com");
|
||||
// Another tab that we'll pretend is hung.
|
||||
let tabHung = BrowserTestUtils.addTab(gBrowser, "http://example.com");
|
||||
await BrowserTestUtils.browserLoaded(tabHung.linkedBrowser);
|
||||
await SpecialPowers.spawn(tabHung.linkedBrowser, [], async () => {
|
||||
// Open an in-process iframe to test toolkit.aboutProcesses.showAllSubframes
|
||||
let frame = content.document.createElement("iframe");
|
||||
content.document.body.appendChild(frame);
|
||||
});
|
||||
observer.observe(tbody, { childList: true });
|
||||
});
|
||||
|
||||
info("Looking at the contents of about:processes");
|
||||
let processesToBeFound = [
|
||||
// The browser process.
|
||||
{
|
||||
name: "browser",
|
||||
type: ["browser"],
|
||||
predicate: row => row.process.type == "browser",
|
||||
},
|
||||
// The hung process.
|
||||
{
|
||||
name: "hung",
|
||||
type: ["web", "webIsolated"],
|
||||
predicate: row =>
|
||||
row.classList.contains("hung") && row.classList.contains("process"),
|
||||
},
|
||||
// Any non-hung process
|
||||
{
|
||||
name: "hung",
|
||||
type: ["web", "webIsolated"],
|
||||
predicate: row =>
|
||||
!row.classList.contains("hung") &&
|
||||
row.classList.contains("process") &&
|
||||
row.process.type == "web",
|
||||
},
|
||||
];
|
||||
for (let finder of processesToBeFound) {
|
||||
info(`Running sanity tests on ${finder.name}`);
|
||||
let row = tbody.firstChild;
|
||||
while (row) {
|
||||
if (finder.predicate(row)) {
|
||||
break;
|
||||
}
|
||||
row = row.nextSibling;
|
||||
}
|
||||
Assert.ok(row, `found a table row for ${finder.name}`);
|
||||
let {
|
||||
memoryResidentContent,
|
||||
cpuContent,
|
||||
pidContent,
|
||||
typeContent,
|
||||
threads,
|
||||
} = extractProcessDetails(row);
|
||||
info("Setting up fake process hang detector");
|
||||
let hungChildID = tabHung.linkedBrowser.frameLoader.childID;
|
||||
|
||||
info("Sanity checks: type");
|
||||
Assert.ok(
|
||||
finder.type.includes(typeContent),
|
||||
`Type ${typeContent} should be one of ${finder.type}`
|
||||
);
|
||||
let doc = tabAboutProcesses.linkedBrowser.contentDocument;
|
||||
let tbody = doc.getElementById("process-tbody");
|
||||
|
||||
info("Sanity checks: pid");
|
||||
let pid = Number.parseInt(pidContent);
|
||||
Assert.ok(pid > 0, `Checking pid ${pidContent}`);
|
||||
Assert.equal(pid, row.process.pid);
|
||||
|
||||
info("Sanity checks: memory resident");
|
||||
testMemory(
|
||||
memoryResidentContent,
|
||||
row.process.totalResidentUniqueSize,
|
||||
row.process.deltaResidentUniqueSize,
|
||||
HARDCODED_ASSUMPTIONS_PROCESS
|
||||
);
|
||||
|
||||
info("Sanity checks: CPU (Total)");
|
||||
testCpu(
|
||||
cpuContent,
|
||||
row.process.totalCpu,
|
||||
row.process.slopeCpu,
|
||||
HARDCODED_ASSUMPTIONS_PROCESS
|
||||
);
|
||||
|
||||
if (!showThreads) {
|
||||
Assert.equal(
|
||||
threads,
|
||||
null,
|
||||
"In hidden threads mode, we shouldn't have any thread summary"
|
||||
);
|
||||
} else {
|
||||
info("Sanity checks: number of threads");
|
||||
let numberOfThreads = Number.parseInt(threads.numberContent);
|
||||
Assert.ok(
|
||||
numberOfThreads >=
|
||||
HARDCODED_ASSUMPTIONS_PROCESS.minimalNumberOfThreads
|
||||
);
|
||||
Assert.ok(
|
||||
numberOfThreads <=
|
||||
HARDCODED_ASSUMPTIONS_PROCESS.maximalNumberOfThreads
|
||||
);
|
||||
Assert.equal(numberOfThreads, row.process.threads.length);
|
||||
|
||||
info("Testing that we can open the list of threads");
|
||||
let twisty = threads.row.getElementsByClassName("twisty")[0];
|
||||
twisty.click();
|
||||
let numberOfThreadsFound = 0;
|
||||
for (
|
||||
let threadRow = threads.row.nextSibling;
|
||||
threadRow && threadRow.classList.contains("thread");
|
||||
threadRow = threadRow.nextSibling
|
||||
) {
|
||||
let children = threadRow.children;
|
||||
let cpuContent = children[2].textContent;
|
||||
let tidContent = document.l10n.getAttributes(children[0].children[0])
|
||||
.args.tid;
|
||||
++numberOfThreadsFound;
|
||||
|
||||
info("Sanity checks: tid");
|
||||
let tid = Number.parseInt(tidContent);
|
||||
Assert.notEqual(tid, 0, "The tid should be set");
|
||||
Assert.equal(tid, threadRow.thread.tid, "Displayed tid is correct");
|
||||
|
||||
info("Sanity checks: CPU (User and Kernel)");
|
||||
testCpu(
|
||||
cpuContent,
|
||||
threadRow.thread.totalCpu,
|
||||
threadRow.thread.slopeCpu,
|
||||
HARDCODED_ASSUMPTIONS_THREAD
|
||||
// Keep informing about:processes that `tabHung` is hung.
|
||||
// Note: this is a background task, do not `await` it.
|
||||
let fakeProcessHangMonitor = async function() {
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
if (!tabHung.linkedBrowser) {
|
||||
// Let's stop spamming as soon as we can.
|
||||
return;
|
||||
}
|
||||
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
Services.obs.notifyObservers(
|
||||
{
|
||||
childID: hungChildID,
|
||||
hangType: Ci.nsIHangReport.PLUGIN_HANG,
|
||||
pluginName: "Fake plug-in",
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIHangReport"]),
|
||||
},
|
||||
"process-hang-report"
|
||||
);
|
||||
}
|
||||
Assert.equal(
|
||||
numberOfThreads,
|
||||
numberOfThreadsFound,
|
||||
"Found as many threads as expected"
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
fakeProcessHangMonitor();
|
||||
|
||||
info("Additional sanity check for all processes");
|
||||
for (let row of document.getElementsByClassName("process")) {
|
||||
let { pidContent, typeContent } = extractProcessDetails(row);
|
||||
Assert.equal(typeContent, row.process.type);
|
||||
Assert.equal(Number.parseInt(pidContent), row.process.pid);
|
||||
info("Waiting for the first update of about:processes");
|
||||
// Wait until the table has first been populated.
|
||||
await TestUtils.waitForCondition(() => tbody.childElementCount);
|
||||
|
||||
info("Waiting for the second update of about:processes");
|
||||
// And wait for another update using a mutation observer, to give our newly created test tab some time
|
||||
// to burn some CPU.
|
||||
await new Promise(resolve => {
|
||||
let observer = new doc.ownerGlobal.MutationObserver(() => {
|
||||
observer.disconnect();
|
||||
resolve();
|
||||
});
|
||||
observer.observe(tbody, { childList: true });
|
||||
});
|
||||
|
||||
info("Looking at the contents of about:processes");
|
||||
let processesToBeFound = [
|
||||
// The browser process.
|
||||
{
|
||||
name: "browser",
|
||||
type: ["browser"],
|
||||
predicate: row => row.process.type == "browser",
|
||||
},
|
||||
// The hung process.
|
||||
{
|
||||
name: "hung",
|
||||
type: ["web", "webIsolated"],
|
||||
predicate: row =>
|
||||
row.classList.contains("hung") && row.classList.contains("process"),
|
||||
},
|
||||
// Any non-hung process
|
||||
{
|
||||
name: "hung",
|
||||
type: ["web", "webIsolated"],
|
||||
predicate: row =>
|
||||
!row.classList.contains("hung") &&
|
||||
row.classList.contains("process") &&
|
||||
row.process.type == "web",
|
||||
},
|
||||
];
|
||||
for (let finder of processesToBeFound) {
|
||||
info(`Running sanity tests on ${finder.name}`);
|
||||
let row = tbody.firstChild;
|
||||
while (row) {
|
||||
if (finder.predicate(row)) {
|
||||
break;
|
||||
}
|
||||
row = row.nextSibling;
|
||||
}
|
||||
Assert.ok(row, `found a table row for ${finder.name}`);
|
||||
let {
|
||||
memoryResidentContent,
|
||||
cpuContent,
|
||||
pidContent,
|
||||
typeContent,
|
||||
threads,
|
||||
} = extractProcessDetails(row);
|
||||
|
||||
info("Sanity checks: type");
|
||||
Assert.ok(
|
||||
finder.type.includes(typeContent),
|
||||
`Type ${typeContent} should be one of ${finder.type}`
|
||||
);
|
||||
|
||||
info("Sanity checks: pid");
|
||||
let pid = Number.parseInt(pidContent);
|
||||
Assert.ok(pid > 0, `Checking pid ${pidContent}`);
|
||||
Assert.equal(pid, row.process.pid);
|
||||
|
||||
info("Sanity checks: memory resident");
|
||||
testMemory(
|
||||
memoryResidentContent,
|
||||
row.process.totalResidentUniqueSize,
|
||||
row.process.deltaResidentUniqueSize,
|
||||
HARDCODED_ASSUMPTIONS_PROCESS
|
||||
);
|
||||
|
||||
info("Sanity checks: CPU (Total)");
|
||||
testCpu(
|
||||
cpuContent,
|
||||
row.process.totalCpu,
|
||||
row.process.slopeCpu,
|
||||
HARDCODED_ASSUMPTIONS_PROCESS
|
||||
);
|
||||
|
||||
// Testing threads.
|
||||
if (!showThreads) {
|
||||
info("In this mode, we shouldn't display any threads");
|
||||
Assert.equal(
|
||||
threads,
|
||||
null,
|
||||
"In hidden threads mode, we shouldn't have any thread summary"
|
||||
);
|
||||
} else {
|
||||
info("Sanity checks: number of threads");
|
||||
let numberOfThreads = Number.parseInt(threads.numberContent);
|
||||
Assert.ok(
|
||||
numberOfThreads >=
|
||||
HARDCODED_ASSUMPTIONS_PROCESS.minimalNumberOfThreads
|
||||
);
|
||||
Assert.ok(
|
||||
numberOfThreads <=
|
||||
HARDCODED_ASSUMPTIONS_PROCESS.maximalNumberOfThreads
|
||||
);
|
||||
Assert.equal(numberOfThreads, row.process.threads.length);
|
||||
|
||||
info("Testing that we can open the list of threads");
|
||||
let twisty = threads.row.getElementsByClassName("twisty")[0];
|
||||
twisty.click();
|
||||
let numberOfThreadsFound = 0;
|
||||
for (
|
||||
let threadRow = threads.row.nextSibling;
|
||||
threadRow && threadRow.classList.contains("thread");
|
||||
threadRow = threadRow.nextSibling
|
||||
) {
|
||||
let children = threadRow.children;
|
||||
let cpuContent = children[2].textContent;
|
||||
let tidContent = document.l10n.getAttributes(
|
||||
children[0].children[0]
|
||||
).args.tid;
|
||||
++numberOfThreadsFound;
|
||||
|
||||
info("Sanity checks: tid");
|
||||
let tid = Number.parseInt(tidContent);
|
||||
Assert.notEqual(tid, 0, "The tid should be set");
|
||||
Assert.equal(tid, threadRow.thread.tid, "Displayed tid is correct");
|
||||
|
||||
info("Sanity checks: CPU (User and Kernel)");
|
||||
testCpu(
|
||||
cpuContent,
|
||||
threadRow.thread.totalCpu,
|
||||
threadRow.thread.slopeCpu,
|
||||
HARDCODED_ASSUMPTIONS_THREAD
|
||||
);
|
||||
}
|
||||
Assert.equal(
|
||||
numberOfThreads,
|
||||
numberOfThreadsFound,
|
||||
"Found as many threads as expected"
|
||||
);
|
||||
}
|
||||
|
||||
// Testing subframes.
|
||||
let foundAtLeastOneInProcessSubframe = false;
|
||||
for (let row of doc.getElementsByClassName("window")) {
|
||||
let subframe = row.win;
|
||||
if (subframe.tab) {
|
||||
continue;
|
||||
}
|
||||
let url = document.l10n.getAttributes(row.children[0].children[0])
|
||||
.args.url;
|
||||
Assert.equal(url, subframe.documentURI.spec);
|
||||
if (!subframe.isProcessRoot) {
|
||||
foundAtLeastOneInProcessSubframe = true;
|
||||
}
|
||||
}
|
||||
if (showAllFrames) {
|
||||
Assert.ok(
|
||||
foundAtLeastOneInProcessSubframe,
|
||||
"Found at least one about:blank in-process subframe"
|
||||
);
|
||||
} else {
|
||||
Assert.ok(
|
||||
!foundAtLeastOneInProcessSubframe,
|
||||
"We shouldn't have any about:blank in-process subframe"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
info("Additional sanity check for all processes");
|
||||
for (let row of document.getElementsByClassName("process")) {
|
||||
let { pidContent, typeContent } = extractProcessDetails(row);
|
||||
Assert.equal(typeContent, row.process.type);
|
||||
Assert.equal(Number.parseInt(pidContent), row.process.pid);
|
||||
}
|
||||
BrowserTestUtils.removeTab(tabAboutProcesses);
|
||||
BrowserTestUtils.removeTab(tabHung);
|
||||
}
|
||||
BrowserTestUtils.removeTab(tabAboutProcesses);
|
||||
BrowserTestUtils.removeTab(tabHung);
|
||||
}
|
||||
|
||||
Services.prefs.clearUserPref("toolkit.aboutProcesses.showThreads");
|
||||
|
|
Загрузка…
Ссылка в новой задаче