[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[vidalia-svn] r3839: Checkpoint my current Breakpad integration stuff, now that t (vidalia/branches/breakpad/src/vidalia)



Author: edmanm
Date: 2009-06-11 03:03:19 -0400 (Thu, 11 Jun 2009)
New Revision: 3839

Modified:
   vidalia/branches/breakpad/src/vidalia/main.cpp
Log:

Checkpoint my current Breakpad integration stuff, now that the VS build issues
are out of the way.


Modified: vidalia/branches/breakpad/src/vidalia/main.cpp
===================================================================
--- vidalia/branches/breakpad/src/vidalia/main.cpp	2009-06-11 06:52:48 UTC (rev 3838)
+++ vidalia/branches/breakpad/src/vidalia/main.cpp	2009-06-11 07:03:19 UTC (rev 3839)
@@ -29,6 +29,9 @@
 #endif
 
 #if defined(USE_BREAKPAD)
+#include <QFileInfo>
+#include <QDir>
+
 #if defined(Q_OS_WIN32)
 #include <client/windows/handler/exception_handler.h>
 #elif defined(Q_OS_MAC)
@@ -39,11 +42,36 @@
 #include <client/solaris/handler/exception_handler.h>
 #endif
 
-static google_breakpad::ExceptionHandler *gExceptionHandler = 0;
-#endif
+/** Pointer to the Breakpad-installed exception handler called if Vidalia
+ * crashes.
+ */
+static google_breakpad::ExceptionHandler *_exceptionHandler = 0;
 
+/** If true, the crash reporting application will be displayed when the
+ * Breakpad-installed exception handler is called. Otherwise, the system
+ * will handle the exception itself.
+ */
+static bool _showCrashReporter = true;
 
-#if defined(USE_BREAKPAD)
+/** Defines the maximum length of the absolute path plus filename of the
+ * crash reporting executable displayed when the exception handler is
+ * called.
+ */
+#define MAX_PATH_LEN  4096
+
+/** Absolute path of the crash reporting application that will be launched
+ * from the exception handler.
+ * \sa setup_exception_handler()
+ */
+static wchar_t _crashReporterAppPath[MAX_PATH_LEN + 1] = L"";
+
+
+/** Breakpad-installed exception handler. This function gets called in the
+ * event of a crash. If _showCrashReporter is true, this will call execute
+ * the crash reporting application, passing it the name and location of the
+ * generated minidump, the absolute path to the (now crashed) Vidalia
+ * executable, and any arguments that may be needed to restart Vidalia.
+ */
 static bool
 minidump_callback(const wchar_t *dump, const wchar_t *id, void *context,
 #if defined(Q_OS_WIN32)
@@ -52,28 +80,85 @@
 #endif
                   bool succeeded)
 {
-  return succeeded;
+  if (! succeeded || ! _showCrashReporter)
+    return false;
+
+  /* Launch the crash reporter with the name and location of the minidump */
+
+  return true;
 }
-#endif
 
-void
-set_exception_handler(const QString &dumpPath)
+/** Installs the Breakpad exception handler and sets the static global
+ * variables used by the exception handler to launch the crash reporting
+ * application. Minidumps will be writen to <b>dumpPath</b>, which will
+ * be created if it doesn't already exist.
+ * \sa remove_exception_handler()
+ */
+bool
+install_exception_handler(const QString &dumpPath)
 {
-#if defined(USE_BREAKPAD)
-  /* XXX: Convert dumpPath to a wchar_t* and pass it to the handler */
-  Q_UNUSED(dumpPath);
+  /* Create a directory for the crash dumps if it doesn't already exist */
+  QDir dumpDir(dumpPath);
+  if (! dumpDir.exists() && ! dumpDir.mkdir(".")) {
+    vWarn("Unable to create crash report directory: %1")
+                            .arg(dumpDir.absolutePath());
+    return false;
+  }
+  vInfo("Storing crash reports in \"%1\"").arg(dumpDir.absolutePath());
 
-  gExceptionHandler = new google_breakpad::ExceptionHandler(
-                            L".",
+
+#if defined(Q_OS_WIN32)
+  /* Set the location of the crash reporting application that will get
+   * launched if Vidalia crashes. On Windows, it is assumed to exist in the
+   * same directory as Vidalia.exe. */
+  QString crashReporterApp = vApp->applicationDirPath() + "/crashreporter.exe";
+  if (QFileInfo(crashReporterApp).isExecutable()
+        && crashReporterApp.length() <= MAX_PATH_LEN) {
+    crashReporterApp.toWCharArray(_crashReporterAppPath);
+    _crashReporterAppPath[crashReporterApp.length()] = L'\0';
+    _showCrashReporter = true;
+    vInfo("Found crash reporting application at \"%1\"").arg(crashReporterApp);
+  }
+#else
+  /* XXX: No crash reporter support available on non-Windows yet. */
+  _showCrashReporter = false;
+#endif
+
+  /* Create the exception handler and specify where the dumps should go */
+  _exceptionHandler = new google_breakpad::ExceptionHandler(
+                            dumpDir.absolutePath().toStdWString(),
                             NULL,
                             minidump_callback,
                             NULL,
+#if defined(Q_OS_WIN32)
                             google_breakpad::ExceptionHandler::HANDLER_ALL);
 #else
-  Q_UNUSED(dumpPath);
+                            true);
 #endif
+  if (! _exceptionHandler) {
+    vWarn("Failed to create Breakpad exception handler. Crash reporting will "
+          "be unavailable.");
+    return true;
+  }
+  vInfo("Successfully installed Breakpad exception handler.");
+  return true;
 }
 
+/** Removes the application's exception handler previously created by
+ * install_exception_handler(). If no exception handler was previously created,
+ * no action will be taken.
+ * \sa install_exception_handler()
+ */
+void
+remove_exception_handler()
+{
+  if (_exceptionHandler) {
+    delete _exceptionHandler;
+    _exceptionHandler = 0;
+  }
+}
+#endif
+
 /** Returns true if there is already another Vidalia process running. */
 bool
 is_vidalia_running(QString pidfile)
@@ -110,9 +195,13 @@
   vNotice("Vidalia %1 using Qt %2").arg(Vidalia::version())
                                    .arg(QT_VERSION_STR);
 
+#if defined(USE_BREAKPAD)
   /* Set the location for crash dumps if we're built with Breakpad */
-  set_exception_handler(Vidalia::dataDirectory());
-
+  if (! install_exception_handler(vidalia.dataDirectory() + "/crashreports")) {
+    vWarn("Unable to setup Breakpad exception handler. Crash reporting "
+          "will be unavailable.");
+  }
+#endif
 #if defined(USE_MARBLE) && defined(Q_OS_WIN32)
   vApp->addLibraryPath(vApp->applicationDirPath() + "/plugins/qt");
 #endif
@@ -172,6 +261,12 @@
   /* Vidalia exited, so cleanup our pidfile and return */
   QFile::remove(pidfile);
   vNotice("Vidalia is exiting cleanly (return code %1).").arg(ret);
+
+#if defined(USE_BREAKPAD)
+  vInfo("Removing Breakpad exception handler.");
+  remove_exception_handler();
+#endif
+
   return ret;
 }