From fea98577d4d501384f7ff08a28832a9a18a3445a Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Fri, 21 Jul 2017 16:16:59 -0700 Subject: [PATCH] Bug 1384336 - Stop using OS-level event loop in content process (r=mstange) MozReview-Commit-ID: 1ouSlgGchWl --- dom/ipc/ContentChild.cpp | 14 ++++++++++++++ dom/ipc/ContentPrefs.cpp | 1 + modules/libpref/init/all.js | 3 +++ toolkit/xre/nsAppRunner.cpp | 18 ++++++++++++++++++ toolkit/xre/nsEmbedFunctions.cpp | 2 +- widget/cocoa/nsAppShell.mm | 10 ++++++++-- widget/nsBaseAppShell.cpp | 8 +++++--- xpcom/build/nsXULAppAPI.h | 7 +++++++ 8 files changed, 57 insertions(+), 6 deletions(-) diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index a121fd7354d8f..f44f6ccee533d 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -1452,6 +1452,11 @@ GetDirectoryPath(const char *aPath) { } #endif // DEBUG +extern "C" { +void CGSSetDenyWindowServerConnections(bool); +void CGSShutdownServerConnections(); +}; + static bool StartMacOSContentSandbox() { @@ -1460,6 +1465,15 @@ StartMacOSContentSandbox() return false; } + if (!XRE_UseNativeEventProcessing()) { + // If we've opened a connection to the window server, shut it down now. Forbid + // future connections as well. We do this for sandboxing, but it also ensures + // that the Activity Monitor will not label the content process as "Not + // responding" because it's not running a native event loop. See bug 1384336. + CGSSetDenyWindowServerConnections(true); + CGSShutdownServerConnections(); + } + nsAutoCString appPath, appBinaryPath, appDir; if (!GetAppPaths(appPath, appBinaryPath, appDir)) { MOZ_CRASH("Error resolving child process path"); diff --git a/dom/ipc/ContentPrefs.cpp b/dom/ipc/ContentPrefs.cpp index 1423f7791ac8d..78ecd55da9f36 100644 --- a/dom/ipc/ContentPrefs.cpp +++ b/dom/ipc/ContentPrefs.cpp @@ -52,6 +52,7 @@ const char* mozilla::dom::ContentPrefs::gInitPrefs[] = { "dom.forms.autocomplete.formautofill", "dom.ipc.processPriorityManager.backgroundGracePeriodMS", "dom.ipc.processPriorityManager.backgroundPerceivableGracePeriodMS", + "dom.ipc.useNativeEventProcessing.content", "dom.max_chrome_script_run_time", "dom.max_script_run_time", "dom.mozBrowserFramesEnabled", diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 763575ecfde99..013cb9f93bf76 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -3239,6 +3239,9 @@ pref("dom.ipc.processCount.file", 1); // WebExtensions only support a single extension process. pref("dom.ipc.processCount.extension", 1); +// Don't use a native event loop in the content process. +pref("dom.ipc.useNativeEventProcessing.content", false); + // Disable support for SVG pref("svg.disabled", false); diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 3532f8c8f9400..2e6d9a3a96798 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -5012,6 +5012,24 @@ XRE_IsContentProcess() return XRE_GetProcessType() == GeckoProcessType_Content; } +bool +XRE_UseNativeEventProcessing() +{ + if (XRE_IsContentProcess()) { + static bool sInited = false; + static bool sUseNativeEventProcessing = false; + if (!sInited) { + Preferences::AddBoolVarCache(&sUseNativeEventProcessing, + "dom.ipc.useNativeEventProcessing.content"); + sInited = true; + } + + return sUseNativeEventProcessing; + } + + return true; +} + // If you add anything to this enum, please update about:support to reflect it enum { kE10sEnabledByUser = 0, diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp index a63ae835cd987..12b96864074fb 100644 --- a/toolkit/xre/nsEmbedFunctions.cpp +++ b/toolkit/xre/nsEmbedFunctions.cpp @@ -839,7 +839,7 @@ XRE_RunAppShell() nsCOMPtr appShell(do_GetService(kAppShellCID)); NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE); #if defined(XP_MACOSX) - { + if (XRE_UseNativeEventProcessing()) { // In content processes that want XPCOM (and hence want // AppShell), we usually run our hybrid event loop through // MessagePump::Run(), by way of nsBaseAppShell::Run(). The diff --git a/widget/cocoa/nsAppShell.mm b/widget/cocoa/nsAppShell.mm index da00f5c474c74..da7bf58708513 100644 --- a/widget/cocoa/nsAppShell.mm +++ b/widget/cocoa/nsAppShell.mm @@ -682,13 +682,19 @@ - (void)beginMenuTracking:(NSNotification*)aNotification; AddScreenWakeLockListener(); } - NS_OBJC_TRY_ABORT([NSApp run]); + // We use the native Gecko event loop in content processes. + nsresult rv = NS_OK; + if (XRE_UseNativeEventProcessing()) { + NS_OBJC_TRY_ABORT([NSApp run]); + } else { + rv = nsBaseAppShell::Run(); + } if (XRE_IsParentProcess()) { RemoveScreenWakeLockListener(); } - return NS_OK; + return rv; } NS_IMETHODIMP diff --git a/widget/nsBaseAppShell.cpp b/widget/nsBaseAppShell.cpp index f32ce613f6584..4421dd54f7c01 100644 --- a/widget/nsBaseAppShell.cpp +++ b/widget/nsBaseAppShell.cpp @@ -46,11 +46,13 @@ nsBaseAppShell::Init() { // Configure ourselves as an observer for the current thread: - nsCOMPtr threadInt = + if (XRE_UseNativeEventProcessing()) { + nsCOMPtr threadInt = do_QueryInterface(NS_GetCurrentThread()); - NS_ENSURE_STATE(threadInt); + NS_ENSURE_STATE(threadInt); - threadInt->SetObserver(this); + threadInt->SetObserver(this); + } nsCOMPtr obsSvc = mozilla::services::GetObserverService(); diff --git a/xpcom/build/nsXULAppAPI.h b/xpcom/build/nsXULAppAPI.h index f9141dfc4be68..4ae3263d2d768 100644 --- a/xpcom/build/nsXULAppAPI.h +++ b/xpcom/build/nsXULAppAPI.h @@ -462,6 +462,13 @@ XRE_API(bool, XRE_API(bool, XRE_IsGPUProcess, ()) +/** + * Returns true if the appshell should run its own native event loop. Returns + * false if we should rely solely on the Gecko event loop. + */ +XRE_API(bool, + XRE_UseNativeEventProcessing, ()) + typedef void (*MainFunction)(void* aData); XRE_API(nsresult,