From 6044ab05f3e17c487105908556bf78641ab3a2df Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Sun, 4 Oct 2015 15:40:51 +0800 Subject: [PATCH] Ignore X Window System errors --- brightray/browser/browser_main_parts.cc | 99 ++++++++++++++++++++++--- brightray/browser/browser_main_parts.h | 1 + 2 files changed, 88 insertions(+), 12 deletions(-) diff --git a/brightray/browser/browser_main_parts.cc b/brightray/browser/browser_main_parts.cc index b69c90f88a..b87be5a8ee 100644 --- a/brightray/browser/browser_main_parts.cc +++ b/brightray/browser/browser_main_parts.cc @@ -11,6 +11,7 @@ #include "base/command_line.h" #include "base/strings/string_number_conversions.h" #include "components/devtools_http_handler/devtools_http_handler.h" +#include "content/public/browser/browser_thread.h" #include "content/public/common/content_switches.h" #include "net/proxy/proxy_resolver_v8.h" @@ -19,21 +20,21 @@ #include "ui/views/widget/desktop_aura/desktop_screen.h" #endif -#if defined(USE_AURA) && defined(USE_X11) -#include "chrome/browser/ui/libgtk2ui/gtk2_ui.h" -#include "ui/views/linux_ui/linux_ui.h" -#include "ui/wm/core/wm_state.h" -#endif - #if defined(TOOLKIT_VIEWS) #include "browser/views/views_delegate.h" #endif -#if defined(OS_LINUX) +#if defined(USE_X11) #include "base/environment.h" #include "base/path_service.h" #include "base/nix/xdg_util.h" +#include "base/thread_task_runner_handle.h" #include "browser/brightray_paths.h" +#include "chrome/browser/ui/libgtk2ui/gtk2_ui.h" +#include "ui/base/x/x11_util.h" +#include "ui/base/x/x11_util_internal.h" +#include "ui/views/linux_ui/linux_ui.h" +#include "ui/wm/core/wm_state.h" #endif #if defined(OS_WIN) @@ -43,6 +44,8 @@ #include "ui/gfx/platform_font_win.h" #endif +using content::BrowserThread; + namespace brightray { namespace { @@ -58,7 +61,14 @@ int GetMinimumFontSize() { } #endif -#if defined(OS_LINUX) +#if defined(USE_X11) +// Indicates that we're currently responding to an IO error (by shutting down). +bool g_in_x11_io_error_handler = false; + +// Number of seconds to wait for UI thread to get an IO error if we get it on +// the background thread. +const int kWaitForUIThreadSeconds = 10; + void OverrideLinuxAppDataPath() { base::FilePath path; if (PathService::Get(DIR_APP_DATA, &path)) @@ -69,6 +79,53 @@ void OverrideLinuxAppDataPath() { base::nix::kDotConfigDir); PathService::Override(DIR_APP_DATA, path); } + +int BrowserX11ErrorHandler(Display* d, XErrorEvent* error) { + if (!g_in_x11_io_error_handler) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&ui::LogErrorEventDescription, d, *error)); + } + return 0; +} + +// This function is used to help us diagnose crash dumps that happen +// during the shutdown process. +NOINLINE void WaitingForUIThreadToHandleIOError() { + // Ensure function isn't optimized away. + asm(""); + sleep(kWaitForUIThreadSeconds); +} + +int BrowserX11IOErrorHandler(Display* d) { + if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { + // Wait for the UI thread (which has a different connection to the X server) + // to get the error. We can't call shutdown from this thread without + // tripping an error. Doing it through a function so that we'll be able + // to see it in any crash dumps. + WaitingForUIThreadToHandleIOError(); + return 0; + } + + // If there's an IO error it likely means the X server has gone away. + // If this CHECK fails, then that means SessionEnding() below triggered some + // code that tried to talk to the X server, resulting in yet another error. + CHECK(!g_in_x11_io_error_handler); + + g_in_x11_io_error_handler = true; + LOG(ERROR) << "X IO error received (X server probably went away)"; + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); + + return 0; +} + +int X11EmptyErrorHandler(Display* d, XErrorEvent* error) { + return 0; +} + +int X11EmptyIOErrorHandler(Display* d) { + return 0; +} #endif } // namespace @@ -84,12 +141,14 @@ void BrowserMainParts::PreEarlyInitialization() { IncreaseFileDescriptorLimit(); #endif -#if defined(USE_AURA) && defined(USE_X11) +#if defined(USE_X11) views::LinuxUI::SetInstance(BuildGtk2UI()); -#endif - -#if defined(OS_LINUX) OverrideLinuxAppDataPath(); + + // Installs the X11 error handlers for the browser process used during + // startup. They simply print error messages and exit because + // we can't shutdown properly while creating and initializing services. + ui::SetX11ErrorHandlers(nullptr, nullptr); #endif } @@ -131,8 +190,24 @@ void BrowserMainParts::PreMainMessageLoopRun() { devtools_http_handler_.reset(DevToolsManagerDelegate::CreateHttpHandler()); } +void BrowserMainParts::PostMainMessageLoopStart() { +#if defined(USE_X11) + // Installs the X11 error handlers for the browser process after the + // main message loop has started. This will allow us to exit cleanly + // if X exits before us. + ui::SetX11ErrorHandlers(BrowserX11ErrorHandler, BrowserX11IOErrorHandler); +#endif +} + void BrowserMainParts::PostMainMessageLoopRun() { browser_context_ = nullptr; + +#if defined(USE_X11) + // Unset the X11 error handlers. The X11 error handlers log the errors using a + // |PostTask()| on the message-loop. But since the message-loop is in the + // process of terminating, this can cause errors. + ui::SetX11ErrorHandlers(X11EmptyErrorHandler, X11EmptyIOErrorHandler); +#endif } int BrowserMainParts::PreCreateThreads() { diff --git a/brightray/browser/browser_main_parts.h b/brightray/browser/browser_main_parts.h index 5ed3e1eb1f..da35d78c22 100644 --- a/brightray/browser/browser_main_parts.h +++ b/brightray/browser/browser_main_parts.h @@ -43,6 +43,7 @@ class BrowserMainParts : public content::BrowserMainParts { void ToolkitInitialized() override; void PreMainMessageLoopStart() override; void PreMainMessageLoopRun() override; + void PostMainMessageLoopStart() override; void PostMainMessageLoopRun() override; int PreCreateThreads() override;