зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1635451
- Minimize content processes' connections to the X server. r=jgilbert,stransky,nika
This patch launches content processes with the `MOZ_HEADLESS` env var set if they're using GTK with an X11 display (and there's no other reason they'd need GTK). The goal is to avoid exhausting Xorg's default limit of 256 clients if there are many content processes due to Fission. If these conditions are met, the content process doesn't need to eagerly connect to the X server. This does not affect the sandbox policy, and content processes can still use X if needed for, e.g., WebGL. The boolean pref `dom.ipc.avoid-gtk`, set by default, controls this feature. In the future it could also be extended to minimize GTK use with Wayland displays. Note that disabling `widget.non-native-theme.enabled`, which is also enabled by default, will restore the use of X11 in all content processes even if this pref is set; the alternative is that widgets wouldn't render in that case. This change will also save some memory for now-unnecessary instances of GTK's global state, and improve content process startup time. Remove also the temp pref dom.ipc.remote-mozIcon because it cannot work anymore with the content process being headless. Differential Revision: https://phabricator.services.mozilla.com/D112197
This commit is contained in:
Родитель
dc3ae62544
Коммит
2257145e1c
|
@ -279,6 +279,7 @@
|
|||
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
# include <gdk/gdk.h>
|
||||
# include "mozilla/WidgetUtilsGtk.h"
|
||||
#endif
|
||||
|
||||
#include "mozilla/RemoteSpellCheckEngineParent.h"
|
||||
|
@ -2545,6 +2546,15 @@ bool ContentParent::BeginSubprocessLaunch(ProcessPriority aPriority) {
|
|||
extraArgs.push_back("-parentBuildID");
|
||||
extraArgs.push_back(parentBuildID.get());
|
||||
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
// This is X11-only pending a solution for WebGL in Wayland mode.
|
||||
if (StaticPrefs::dom_ipc_avoid_gtk() &&
|
||||
StaticPrefs::widget_non_native_theme_enabled() &&
|
||||
widget::GdkIsX11Display()) {
|
||||
mSubprocess->SetEnv("MOZ_HEADLESS", "1");
|
||||
}
|
||||
#endif
|
||||
|
||||
// See also ActorDealloc.
|
||||
mSelfRef = this;
|
||||
mLaunchYieldTS = TimeStamp::Now();
|
||||
|
|
|
@ -37,3 +37,6 @@ support-files = file_dummy.html
|
|||
skip-if =
|
||||
verify
|
||||
fission && os == "linux" && asan # Bug 1713905 - new Fission platform triage
|
||||
[browser_very_fission.js]
|
||||
support-files = file_dummy.html
|
||||
run-if = widget == "gtk"
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/* 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";
|
||||
|
||||
// This test creates a large number of content processes as a
|
||||
// regression test for bug 1635451.
|
||||
|
||||
const TEST_PAGE =
|
||||
"http://mochi.test:8888/browser/dom/ipc/tests/file_dummy.html";
|
||||
|
||||
const NUM_TABS = 256;
|
||||
|
||||
add_task(async () => {
|
||||
let promises = [];
|
||||
for (let i = 0; i < NUM_TABS; ++i) {
|
||||
promises.push(
|
||||
BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
opening: TEST_PAGE,
|
||||
waitForLoad: true,
|
||||
forceNewProcess: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
let tabs = [];
|
||||
for (const p of promises) {
|
||||
tabs.push(await p);
|
||||
}
|
||||
|
||||
ok(true, "All of the tabs loaded");
|
||||
|
||||
for (const t of tabs) {
|
||||
BrowserTestUtils.removeTab(t);
|
||||
}
|
||||
});
|
|
@ -17,14 +17,24 @@ using namespace mozilla::widget;
|
|||
static class GLContextProviderX11 sGLContextProviderX11;
|
||||
static class GLContextProviderEGL sGLContextProviderEGL;
|
||||
|
||||
// Note that if there is no GTK display, `GdkIsX11Display` and
|
||||
// `GdkIsWaylandDisplay` will both return false. That case can
|
||||
// currently happen only in X11 mode if the pref `dom.ipc.avoid-gtk`
|
||||
// is set (and applicable to this process). Thus, these conditionals
|
||||
// check for the presence of Wayland rather than the absence of X11.
|
||||
//
|
||||
// In the future we'll want `dom.ipc.avoid-gtk` to also apply to
|
||||
// Wayland; at that time we'll need another way to communicate the
|
||||
// choice of window system.
|
||||
|
||||
already_AddRefed<GLContext> GLContextProviderWayland::CreateForCompositorWidget(
|
||||
CompositorWidget* aCompositorWidget, bool aHardwareWebRender,
|
||||
bool aForceAccelerated) {
|
||||
if (GdkIsX11Display()) {
|
||||
return sGLContextProviderX11.CreateForCompositorWidget(
|
||||
if (GdkIsWaylandDisplay()) {
|
||||
return sGLContextProviderEGL.CreateForCompositorWidget(
|
||||
aCompositorWidget, aHardwareWebRender, aForceAccelerated);
|
||||
} else {
|
||||
return sGLContextProviderEGL.CreateForCompositorWidget(
|
||||
return sGLContextProviderX11.CreateForCompositorWidget(
|
||||
aCompositorWidget, aHardwareWebRender, aForceAccelerated);
|
||||
}
|
||||
}
|
||||
|
@ -32,28 +42,28 @@ already_AddRefed<GLContext> GLContextProviderWayland::CreateForCompositorWidget(
|
|||
/*static*/
|
||||
already_AddRefed<GLContext> GLContextProviderWayland::CreateHeadless(
|
||||
const GLContextCreateDesc& desc, nsACString* const out_failureId) {
|
||||
if (GdkIsX11Display()) {
|
||||
return sGLContextProviderX11.CreateHeadless(desc, out_failureId);
|
||||
} else {
|
||||
if (GdkIsWaylandDisplay()) {
|
||||
return sGLContextProviderEGL.CreateHeadless(desc, out_failureId);
|
||||
} else {
|
||||
return sGLContextProviderX11.CreateHeadless(desc, out_failureId);
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/
|
||||
GLContext* GLContextProviderWayland::GetGlobalContext() {
|
||||
if (GdkIsX11Display()) {
|
||||
return sGLContextProviderX11.GetGlobalContext();
|
||||
} else {
|
||||
if (GdkIsWaylandDisplay()) {
|
||||
return sGLContextProviderEGL.GetGlobalContext();
|
||||
} else {
|
||||
return sGLContextProviderX11.GetGlobalContext();
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/
|
||||
void GLContextProviderWayland::Shutdown() {
|
||||
if (GdkIsX11Display()) {
|
||||
sGLContextProviderX11.Shutdown();
|
||||
} else {
|
||||
if (GdkIsWaylandDisplay()) {
|
||||
sGLContextProviderEGL.Shutdown();
|
||||
} else {
|
||||
sGLContextProviderX11.Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/gfx/Swizzle.h"
|
||||
#include "mozilla/ipc/ByteBuf.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/StaticPrefs_dom.h"
|
||||
#include <algorithm>
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
@ -407,8 +405,7 @@ nsresult nsIconChannel::Init(nsIURI* aURI) {
|
|||
nsCOMPtr<nsIInputStream> stream;
|
||||
|
||||
using ContentChild = mozilla::dom::ContentChild;
|
||||
auto* contentChild = ContentChild::GetSingleton();
|
||||
if (contentChild && mozilla::StaticPrefs::dom_ipc_remote_mozIcon()) {
|
||||
if (auto* contentChild = ContentChild::GetSingleton()) {
|
||||
// Get the icon via IPC and translate the promise of a ByteBuf
|
||||
// into an actually-existing channel.
|
||||
RefPtr<ContentChild::GetSystemIconPromise> icon =
|
||||
|
|
|
@ -6,18 +6,6 @@
|
|||
|
||||
add_task(async function test_mozicon_file_no_sandbox() {
|
||||
assertFileProcess();
|
||||
assertMozIconIsRemote();
|
||||
await createMozIconInFile("txt");
|
||||
await createMozIconInFile("exe");
|
||||
await createMozIconInFile("non-existent-bidule");
|
||||
});
|
||||
|
||||
add_task(async function test_mozicon_file_no_sandbox_no_remote() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["dom.ipc.remote-mozIcon", false]],
|
||||
});
|
||||
assertFileProcess();
|
||||
assertMozIconIsNotRemote();
|
||||
await createMozIconInFile("txt");
|
||||
await createMozIconInFile("exe");
|
||||
await createMozIconInFile("non-existent-bidule");
|
||||
|
|
|
@ -11,17 +11,3 @@ add_task(async function test_mozicon_file_with_sandbox() {
|
|||
await createMozIconInFile("exe");
|
||||
await createMozIconInFile("non-existent-bidule");
|
||||
});
|
||||
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1695381#c0
|
||||
// with sandbox and no remote enabled, this is expected to fail
|
||||
add_task(async function test_mozicon_file_with_sandbox_no_remote() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["dom.ipc.remote-mozIcon", false]],
|
||||
});
|
||||
assertFileProcess();
|
||||
assertSandboxHeadless();
|
||||
assertMozIconIsNotRemote();
|
||||
await createMozIconInFile("txt", false);
|
||||
await createMozIconInFile("exe", false);
|
||||
await createMozIconInFile("non-existent-bidule", false);
|
||||
});
|
||||
|
|
|
@ -3,10 +3,6 @@ support-files =
|
|||
head.js
|
||||
prefs =
|
||||
security.sandbox.content.headless=true
|
||||
skip-if =
|
||||
(os != 'linux') # the pref is only used on linux
|
||||
tsan # timeout on test_mozicon_file_with_sandbox_no_remote
|
||||
asan # timeout on test_mozicon_file_with_sandbox_no_remote
|
||||
ccov # timeout on test_mozicon_file_with_sandbox_no_remote
|
||||
skip-if = (os != 'linux') # the pref is only used on linux
|
||||
|
||||
[browser_mozicon_file_sandbox_headless.js]
|
||||
|
|
|
@ -42,14 +42,6 @@ function assertSandboxHeadless() {
|
|||
assertPrefVal("security.sandbox.content.headless", true);
|
||||
}
|
||||
|
||||
function assertMozIconIsRemote() {
|
||||
assertPrefVal("dom.ipc.remote-mozIcon", true);
|
||||
}
|
||||
|
||||
function assertMozIconIsNotRemote() {
|
||||
assertPrefVal("dom.ipc.remote-mozIcon", false);
|
||||
}
|
||||
|
||||
function getPage() {
|
||||
let filePage = undefined;
|
||||
const { Services } = ChromeUtils.import(
|
||||
|
|
|
@ -603,6 +603,13 @@ uint32_t GeckoChildProcessHost::sNextUniqueID = 1;
|
|||
/* static */
|
||||
uint32_t GeckoChildProcessHost::GetUniqueID() { return sNextUniqueID++; }
|
||||
|
||||
/* static */
|
||||
void GeckoChildProcessHost::SetEnv(const char* aKey, const char* aValue) {
|
||||
MOZ_ASSERT(mLaunchOptions);
|
||||
mLaunchOptions->env_map[ENVIRONMENT_STRING(aKey)] =
|
||||
ENVIRONMENT_STRING(aValue);
|
||||
}
|
||||
|
||||
void GeckoChildProcessHost::PrepareLaunch() {
|
||||
if (CrashReporter::GetEnabled()) {
|
||||
CrashReporter::OOPInit();
|
||||
|
|
|
@ -84,6 +84,10 @@ class GeckoChildProcessHost : public ChildProcessHost,
|
|||
|
||||
static uint32_t GetUniqueID();
|
||||
|
||||
// Call this before launching to set an environment variable for the
|
||||
// child process. The arguments must be UTF-8.
|
||||
void SetEnv(const char* aKey, const char* aValue);
|
||||
|
||||
// Does not block. The IPC channel may not be initialized yet, and
|
||||
// the child process may or may not have been created when this
|
||||
// method returns.
|
||||
|
|
|
@ -2261,12 +2261,6 @@
|
|||
value: 500
|
||||
mirror: always
|
||||
|
||||
# Temporary pref to allow disabling remoting of MozIcon
|
||||
- name: dom.ipc.remote-mozIcon
|
||||
type: bool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
#ifdef MOZ_ENABLE_FORKSERVER
|
||||
- name: dom.ipc.forkserver.enable
|
||||
type: bool
|
||||
|
@ -2274,6 +2268,21 @@
|
|||
mirror: once
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
#
|
||||
# Avoid the use of GTK in content processes if possible, by running
|
||||
# them in headless mode, to conserve resources (e.g., connections to
|
||||
# the X server). See the usage in `ContentParent.cpp` for the full
|
||||
# definition of "if possible".
|
||||
#
|
||||
# This does not affect sandbox policies; content processes may still
|
||||
# dynamically connect to the display server for, e.g., WebGL.
|
||||
- name: dom.ipc.avoid-gtk
|
||||
type: bool
|
||||
value: true
|
||||
mirror: always
|
||||
#endif
|
||||
|
||||
# Whether or not to collect a paired minidump when force-killing a
|
||||
# content process.
|
||||
- name: dom.ipc.tabs.createKillHardCrashReports
|
||||
|
|
|
@ -34,8 +34,6 @@ const kStrictKeyPressEvents =
|
|||
SpecialPowers.getBoolPref("dom.keyboardevent.keypress.dispatch_non_printable_keys_only_system_group_in_content");
|
||||
const kStrictKeyDownKeyUpEvents =
|
||||
SpecialPowers.getBoolPref("dom.keyboardevent.dispatch_during_composition");
|
||||
const kIsHeadless =
|
||||
SpecialPowers.Cc["@mozilla.org/gfx/info;1"].getService(SpecialPowers.Ci.nsIGfxInfo).isHeadless;
|
||||
|
||||
info("\nProfile::EventUtilsLoadTime: " + (loadTime - start) + "\n");
|
||||
function starttest() {
|
||||
|
@ -48,6 +46,10 @@ function starttest() {
|
|||
check = true;
|
||||
}
|
||||
|
||||
const kIsHeadless = await SpecialPowers.spawnChrome([], () => {
|
||||
return Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo).isHeadless;
|
||||
});
|
||||
|
||||
if (navigator.appVersion.includes("Android")) {
|
||||
// This is the workaround for test failure on debug build.
|
||||
await SpecialPowers.pushPrefEnv({set: [["apz.zoom-to-focused-input.enabled", false]]});
|
||||
|
|
Загрузка…
Ссылка в новой задаче