Ignore X Window System errors

This commit is contained in:
Cheng Zhao 2015-10-04 15:40:51 +08:00
parent 5a97cfaa64
commit 6044ab05f3
2 changed files with 88 additions and 12 deletions

View file

@ -11,6 +11,7 @@
#include "base/command_line.h" #include "base/command_line.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "components/devtools_http_handler/devtools_http_handler.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 "content/public/common/content_switches.h"
#include "net/proxy/proxy_resolver_v8.h" #include "net/proxy/proxy_resolver_v8.h"
@ -19,21 +20,21 @@
#include "ui/views/widget/desktop_aura/desktop_screen.h" #include "ui/views/widget/desktop_aura/desktop_screen.h"
#endif #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) #if defined(TOOLKIT_VIEWS)
#include "browser/views/views_delegate.h" #include "browser/views/views_delegate.h"
#endif #endif
#if defined(OS_LINUX) #if defined(USE_X11)
#include "base/environment.h" #include "base/environment.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "base/nix/xdg_util.h" #include "base/nix/xdg_util.h"
#include "base/thread_task_runner_handle.h"
#include "browser/brightray_paths.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 #endif
#if defined(OS_WIN) #if defined(OS_WIN)
@ -43,6 +44,8 @@
#include "ui/gfx/platform_font_win.h" #include "ui/gfx/platform_font_win.h"
#endif #endif
using content::BrowserThread;
namespace brightray { namespace brightray {
namespace { namespace {
@ -58,7 +61,14 @@ int GetMinimumFontSize() {
} }
#endif #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() { void OverrideLinuxAppDataPath() {
base::FilePath path; base::FilePath path;
if (PathService::Get(DIR_APP_DATA, &path)) if (PathService::Get(DIR_APP_DATA, &path))
@ -69,6 +79,53 @@ void OverrideLinuxAppDataPath() {
base::nix::kDotConfigDir); base::nix::kDotConfigDir);
PathService::Override(DIR_APP_DATA, path); 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 #endif
} // namespace } // namespace
@ -84,12 +141,14 @@ void BrowserMainParts::PreEarlyInitialization() {
IncreaseFileDescriptorLimit(); IncreaseFileDescriptorLimit();
#endif #endif
#if defined(USE_AURA) && defined(USE_X11) #if defined(USE_X11)
views::LinuxUI::SetInstance(BuildGtk2UI()); views::LinuxUI::SetInstance(BuildGtk2UI());
#endif
#if defined(OS_LINUX)
OverrideLinuxAppDataPath(); 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 #endif
} }
@ -131,8 +190,24 @@ void BrowserMainParts::PreMainMessageLoopRun() {
devtools_http_handler_.reset(DevToolsManagerDelegate::CreateHttpHandler()); 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() { void BrowserMainParts::PostMainMessageLoopRun() {
browser_context_ = nullptr; 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() { int BrowserMainParts::PreCreateThreads() {

View file

@ -43,6 +43,7 @@ class BrowserMainParts : public content::BrowserMainParts {
void ToolkitInitialized() override; void ToolkitInitialized() override;
void PreMainMessageLoopStart() override; void PreMainMessageLoopStart() override;
void PreMainMessageLoopRun() override; void PreMainMessageLoopRun() override;
void PostMainMessageLoopStart() override;
void PostMainMessageLoopRun() override; void PostMainMessageLoopRun() override;
int PreCreateThreads() override; int PreCreateThreads() override;