diff --git a/autobuild.xml b/autobuild.xml
index 3bb082e87..5edc42b07 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -389,6 +389,54 @@
version
2.3
+ crashpad
+
curl
copyright
@@ -1237,104 +1285,6 @@
version
1.0pre3.190390340
- google_breakpad
-
- copyright
- Copyright (c) 2006, Google Inc.
- description
- Breakpad is a crossplatform library for capturing crash callstacks and runtime data.
- license
- bsd
- license_file
- LICENSES/google_breakpad.txt
- name
- google_breakpad
- platforms
-
- darwin
-
- archive
-
- hash
- 9f963eb1728e6d5077d4feba805d4896
- hash_algorithm
- md5
- url
- https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/google_breakpad-9e60a27-darwin-201511222009.tar.bz2
-
- name
- darwin
-
- darwin64
-
- archive
-
- hash
- 2d43c6a149cd9c89ba19e884579b1e25
- url
- http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1836/4096/google_breakpad-1413.501824-darwin64-501824.tar.bz2
-
- name
- darwin64
-
- linux
-
- archive
-
- hash
- 52257e5eb166a0b69c9c0c38f6e1920e
- url
- http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273079/arch/Linux/installer/google_breakpad-0.0.0-rev1099-linux-20130329.tar.bz2
-
- name
- linux
-
- linux64
-
- archive
-
- hash
- 3709a51d4d5dff5ec0c4656623eaa05d
- hash_algorithm
- md5
- url
- http://depot.alchemyviewer.org/pub/linux64/lib-trusty/google_breakpad-9e60a27-linux64-201603240004.tar.bz2
-
- name
- linux64
-
- windows
-
- archive
-
- hash
- fa7f683ba4ddd7db777c78c8213d2e46
- hash_algorithm
- md5
- url
- https://depot.alchemyviewer.org/pub/windows/lib-vc141/google_breakpad-7398ce15b79da-windows-201703090621.tar.bz2
-
- name
- windows
-
- windows64
-
- archive
-
- hash
- 71ffc5cae4da7e2e7aac856da44cb8c4
- hash_algorithm
- md5
- url
- https://depot.alchemyviewer.org/pub/windows64/lib-vc141/google_breakpad-7398ce15b79da-windows64-201703081616.tar.bz2
-
- name
- windows64
-
-
- version
- 9e60a27
-
gperftools
copyright
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index 32be5e4b4..dede5fa20 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -17,19 +17,6 @@ set(CMAKE_C_FLAGS_RELEASE
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
"-DLL_RELEASE=1 -D_SECURE_SCL=0 -DNDEBUG -DLL_RELEASE_WITH_DEBUG_INFO=1")
-# Configure crash reporting
-set(RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in release builds")
-set(NON_RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in developer builds")
-
-if(RELEASE_CRASH_REPORTING)
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DLL_SEND_CRASH_REPORTS=1")
-endif()
-
-if(NON_RELEASE_CRASH_REPORTING)
- set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DLL_SEND_CRASH_REPORTS=1")
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DLL_SEND_CRASH_REPORTS=1")
-endif()
-
# Don't bother with a MinSizeRel build.
set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release;Debug" CACHE STRING
"Supported build types." FORCE)
@@ -55,6 +42,14 @@ if (WINDOWS)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE")
endif (WORD_SIZE EQUAL 32)
+ if (FULL_DEBUG_SYMS OR USE_CRASHPAD)
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEBUG:FULL")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUG:FULL")
+ else ()
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEBUG:FASTLINK")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUG:FASTLINK")
+ endif ()
+
if (USE_LTO)
if(INCREMENTAL_LINK)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LTCG:INCREMENTAL")
@@ -306,6 +301,13 @@ endif (LINUX OR DARWIN)
if (STANDALONE)
add_definitions(-DLL_STANDALONE=1)
else (STANDALONE)
+ #Enforce compile-time correctness for fmt strings
+ add_definitions(-DFMT_STRING_ALIAS=1)
+
+ if(USE_CRASHPAD)
+ add_definitions(-DUSE_CRASHPAD=1 -DCRASHPAD_URL="${CRASHPAD_URL}")
+ endif()
+
set(${ARCH}_linux_INCLUDES
atk-1.0
cairo
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 0431ff6bb..8202868a1 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -22,6 +22,7 @@ set(cmake_SOURCE_FILES
ConfigurePkgConfig.cmake
CURL.cmake
Copy3rdPartyLibs.cmake
+ CrashPad.cmake
Cwdebug.cmake
DBusGlib.cmake
DeploySharedLibs.cmake
@@ -32,7 +33,6 @@ set(cmake_SOURCE_FILES
FindCARes.cmake
FindColladadom.cmake
FindGLOD.cmake
- FindGoogleBreakpad.cmake
FindGooglePerfTools.cmake
FindHunSpell.cmake
FindNDOF.cmake
@@ -47,7 +47,6 @@ set(cmake_SOURCE_FILES
GStreamer010Plugin.cmake
Glui.cmake
Glut.cmake
- GoogleBreakpad.cmake
GooglePerfTools.cmake
Hunspell.cmake
JPEG.cmake
diff --git a/indra/cmake/CrashPad.cmake b/indra/cmake/CrashPad.cmake
new file mode 100644
index 000000000..d3f4ed6b7
--- /dev/null
+++ b/indra/cmake/CrashPad.cmake
@@ -0,0 +1,22 @@
+# -*- cmake -*-
+include(Prebuilt)
+include(Variables)
+
+if(USE_CRASHPAD)
+
+if (USESYSTEMLIBS)
+else (USESYSTEMLIBS)
+ use_prebuilt_binary(crashpad)
+ if (WINDOWS)
+ set(CRASHPAD_LIBRARIES
+ debug client.lib util.lib base.lib
+ optimized client.lib util.lib base.lib)
+ elseif (LINUX)
+
+ else (DARWIN)
+
+ endif ()
+ set(CRASHPAD_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/crashpad)
+endif (USESYSTEMLIBS)
+
+endif()
diff --git a/indra/cmake/FindGoogleBreakpad.cmake b/indra/cmake/FindGoogleBreakpad.cmake
deleted file mode 100644
index 18e0b56ed..000000000
--- a/indra/cmake/FindGoogleBreakpad.cmake
+++ /dev/null
@@ -1,40 +0,0 @@
-# -*- cmake -*-
-
-# - Find Google BreakPad
-# Find the Google BreakPad includes and library
-# This module defines
-# BREAKPAD_INCLUDE_DIRECTORIES, where to find the Goole BreakPad includes.
-# BREAKPAD_EXCEPTION_HANDLER_LIBRARIES, the libraries needed to use Google BreakPad.
-# BREAKPAD_EXCEPTION_HANDLER_FOUND, If false, do not try to use Google BreakPad.
-# also defined, but not for general use are
-# BREAKPAD_EXCEPTION_HANDLER_LIBRARY, where to find the Google BreakPad library.
-
-FIND_PATH(BREAKPAD_INCLUDE_DIRECTORIES common/using_std_string.h PATH_SUFFIXES google_breakpad)
-
-SET(BREAKPAD_EXCEPTION_HANDLER_NAMES ${BREAKPAD_EXCEPTION_HANDLER_NAMES} breakpad_client)
-FIND_LIBRARY(BREAKPAD_EXCEPTION_HANDLER_LIBRARY
- NAMES ${BREAKPAD_EXCEPTION_HANDLER_NAMES}
- )
-
-IF (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_INCLUDE_DIRECTORIES)
- SET(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES ${BREAKPAD_EXCEPTION_HANDLER_LIBRARY})
- SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "YES")
-ELSE (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_INCLUDE_DIRECTORIES)
- SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "NO")
-ENDIF (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_INCLUDE_DIRECTORIES)
-
-
-IF (BREAKPAD_EXCEPTION_HANDLER_FOUND)
- IF (NOT BREAKPAD_EXCEPTION_HANDLER_FIND_QUIETLY)
- MESSAGE(STATUS "Found Google BreakPad: ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES}")
- ENDIF (NOT BREAKPAD_EXCEPTION_HANDLER_FIND_QUIETLY)
-ELSE (BREAKPAD_EXCEPTION_HANDLER_FOUND)
- IF (BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED)
- MESSAGE(FATAL_ERROR "Could not find Google BreakPad library")
- ENDIF (BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED)
-ENDIF (BREAKPAD_EXCEPTION_HANDLER_FOUND)
-
-MARK_AS_ADVANCED(
- BREAKPAD_EXCEPTION_HANDLER_LIBRARY
- BREAKPAD_INCLUDE_DIRECTORIES
- )
diff --git a/indra/cmake/GoogleBreakpad.cmake b/indra/cmake/GoogleBreakpad.cmake
deleted file mode 100644
index de899a462..000000000
--- a/indra/cmake/GoogleBreakpad.cmake
+++ /dev/null
@@ -1,26 +0,0 @@
-# -*- cmake -*-
-include(Prebuilt)
-
-if (STANDALONE)
- set(BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED ON)
- include(FindGoogleBreakpad)
-else (STANDALONE)
- use_prebuilt_binary(google_breakpad)
- if (DARWIN)
- set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES exception_handler)
- endif (DARWIN)
- if (LINUX)
- set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES breakpad_client)
- endif (LINUX)
- if (WINDOWS)
- set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES exception_handler crash_generation_client crash_generation_server common)
- endif (WINDOWS)
- # yes, this does look dumb, no, it's not incorrect
- # I think it's incorrect: the second one should go --Aleric
- set(BREAKPAD_INCLUDE_DIRECTORIES
- ${LIBS_PREBUILT_DIR}/include/google_breakpad
- ${LIBS_PREBUILT_LEGACY_DIR}/include/google_breakpad
- ${LIBS_PREBUILT_DIR}/include/google_breakpad/google_breakpad
- ${LIBS_PREBUILT_LEGACY_DIR}/include/google_breakpad/google_breakpad
- )
-endif (STANDALONE)
diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake
index 189efe536..51e10a09a 100644
--- a/indra/cmake/Variables.cmake
+++ b/indra/cmake/Variables.cmake
@@ -36,6 +36,11 @@ option(USE_PRECOMPILED_HEADERS "Enable use of precompiled header directives wher
option(USE_LTO "Enable Whole Program Optimization and related folding and binary reduction routines" OFF)
option(UNATTENDED "Disable use of uneeded tooling for automated builds" OFF)
+# Configure crash reporting
+option(USE_CRASHPAD "Build support for crashpad reporting engine" OFF)
+set(CRASHPAD_URL "" CACHE STRING "Crashpad endpoint url")
+set(VIEWER_SYMBOL_FILE "" CACHE STRING "Name of tarball into which to place symbol files")
+
# Media Plugins
option(ENABLE_MEDIA_PLUGINS "Turn off building media plugins if they are imported by third-party library mechanism" ON)
option(LIBVLCPLUGIN "Turn off building support for libvlc plugin" ON)
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 6479c7bca..cae62271d 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -13,7 +13,6 @@ include(Boost)
include(OpenSSL)
include(LLSharedLibs)
include(Json)
-include(GoogleBreakpad)
include(Copy3rdPartyLibs)
include(ZLIB)
include(URIPARSER)
@@ -291,7 +290,6 @@ target_link_libraries(
llcommon
PUBLIC
absl::hash
- ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES}
${APRUTIL_LIBRARIES}
${APR_LIBRARIES}
${EXPAT_LIBRARIES}
diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h
index 142f47e2a..8fa21bd7e 100644
--- a/indra/llcommon/indra_constants.h
+++ b/indra/llcommon/indra_constants.h
@@ -368,13 +368,6 @@ const U32 MAP_ITEM_CLASSIFIED = 0x08;
const U32 MAP_ITEM_ADULT_EVENT = 0x09;
const U32 MAP_ITEM_LAND_FOR_SALE_ADULT = 0x0a;
-// Crash reporter behavior
-const char* const CRASH_SETTINGS_FILE = "settings_crash_behavior.xml";
-const char* const CRASH_BEHAVIOR_SETTING = "CrashSubmitBehavior";
-const S32 CRASH_BEHAVIOR_ASK = 0;
-const S32 CRASH_BEHAVIOR_ALWAYS_SEND = 1;
-const S32 CRASH_BEHAVIOR_NEVER_SEND = 2;
-
// Export/Import return values
const S32 EXPORT_SUCCESS = 0;
const S32 EXPORT_ERROR_PERMISSIONS = -1;
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index b6498ffbf..36c6b0f61 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -25,9 +25,8 @@
*/
#include "linden_common.h"
-#include "llapp.h"
-#include
+#include "llapp.h"
#ifdef LL_DARWIN
#include
@@ -45,7 +44,6 @@
#include "llstl.h" // for DeletePointer()
#include "llstring.h"
#include "lleventtimer.h"
-#include "exception_handler.h"
//
// Signal handling
@@ -57,12 +55,6 @@
LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop);
BOOL ConsoleCtrlHandler(DWORD fdwCtrlType);
-bool windows_post_minidump_callback(const wchar_t* dump_path,
- const wchar_t* minidump_id,
- void* context,
- EXCEPTION_POINTERS* exinfo,
- MDRawAssertionInfo* assertion,
- bool succeeded);
#else
# include
# include // for fork()
@@ -70,18 +62,6 @@ bool windows_post_minidump_callback(const wchar_t* dump_path,
void setup_signals();
void default_unix_signal_handler(int signum, siginfo_t *info, void *);
-#if LL_LINUX
-#include "client/linux/handler/minidump_descriptor.h"
-static bool unix_minidump_callback(const google_breakpad::MinidumpDescriptor& minidump_desc,
- void* context,
- bool succeeded);
-#else
-// Called by breakpad exception handler after the minidump has been generated.
-bool unix_post_minidump_callback(const char *dump_dir,
- const char *minidump_id,
- void *context, bool succeeded);
-#endif
-
# if LL_DARWIN
/* OSX doesn't support SIGRT* */
S32 LL_SMACKDOWN_SIGNAL = SIGUSR1;
@@ -98,7 +78,7 @@ S32 LL_HEARTBEAT_SIGNAL = (SIGRTMAX >= 0) ? (SIGRTMAX-0) : SIGUSR2;
#endif // LL_WINDOWS
// the static application instance
-LLApp* LLApp::sApplication = NULL;
+LLApp* LLApp::sApplication = nullptr;
// Allows the generation of core files for post mortem under gdb
// and disables crashlogger
@@ -110,7 +90,7 @@ BOOL LLApp::sLogInSignal = FALSE;
// static
LLApp::EAppStatus LLApp::sStatus = LLApp::APP_STATUS_STOPPED; // Keeps track of application status
-LLAppErrorHandler LLApp::sErrorHandler = NULL;
+LLAppErrorHandler LLApp::sErrorHandler = nullptr;
BOOL LLApp::sErrorThreadRunning = FALSE;
#if !LL_WINDOWS
LLApp::child_map LLApp::sChildMap;
@@ -119,13 +99,12 @@ LLAppChildCallback LLApp::sDefaultChildCallback = NULL;
#endif
-LLApp::LLApp() : mThreadErrorp(NULL)
+LLApp::LLApp()
+ : mThreadErrorp(nullptr)
{
commonCtor();
}
-static void* sCrashLoggerReserve = NULL;
-
void LLApp::commonCtor()
{
// Set our status to running
@@ -150,34 +129,11 @@ void LLApp::commonCtor()
// Set the application to this instance.
sApplication = this;
- mExceptionHandler = 0;
-
-#if LL_WINDOWS
- sCrashLoggerReserve = VirtualAlloc(NULL, 512*1024, MEM_COMMIT|MEM_RESERVE, PAGE_NOACCESS);
-#else
- sCrashLoggerReserve = malloc(512*1024);
-#endif
-
// initialize the buffer to write the minidump filename to
// (this is used to avoid allocating memory in the crash handler)
- memset(mMinidumpPath, 0, MAX_MINDUMP_PATH_LENGTH);
mCrashReportPipeStr = L"\\\\.\\pipe\\LLCrashReporterPipe";
}
-#if LL_WINDOWS
-static bool clear_CrashLoggerReserve_callback(void* context, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion)
-{
- VirtualFree(sCrashLoggerReserve, 0, MEM_RELEASE);
- return true;
-}
-#else
-static bool clear_CrashLoggerReserve_callback(void* context)
-{
- free(sCrashLoggerReserve);
- return true;
-}
-#endif
-
LLApp::LLApp(LLErrorThread *error_thread) :
mThreadErrorp(error_thread)
{
@@ -198,11 +154,9 @@ LLApp::~LLApp()
if (mThreadErrorp)
{
delete mThreadErrorp;
- mThreadErrorp = NULL;
+ mThreadErrorp = nullptr;
}
- if(mExceptionHandler != 0) delete mExceptionHandler;
-
LLCommon::cleanupClass();
}
@@ -216,8 +170,8 @@ LLApp* LLApp::instance()
LLSD LLApp::getOption(const std::string& name) const
{
LLSD rv;
- LLSD::array_const_iterator iter = mOptions.beginArray();
- LLSD::array_const_iterator end = mOptions.endArray();
+ auto iter = mOptions.beginArray();
+ auto end = mOptions.endArray();
for(; iter != end; ++iter)
{
rv = (*iter)[name];
@@ -264,9 +218,9 @@ bool LLApp::parseCommandOptions(int argc, char** argv)
#if LL_WINDOWS
//Windows changed command line parsing. Deal with it.
- S32 slen = value.length() - 1;
- S32 start = 0;
- S32 end = slen;
+ size_t slen = value.length() - 1;
+ size_t start = 0;
+ size_t end = slen;
if (argv[ii][start]=='"')start++;
if (argv[ii][end]=='"')end--;
if (start!=0 || end!=slen)
@@ -343,92 +297,17 @@ void LLApp::setupErrorHandling()
// Error handling is done by starting up an error handling thread, which just sleeps and
// occasionally checks to see if the app is in an error state, and sees if it needs to be run.
-#if LL_WINDOWS
-
-#if LL_SEND_CRASH_REPORTS
- EnableCrashingOnCrashes();
-
- // This sets a callback to handle w32 signals to the console window.
- // The viewer shouldn't be affected, sicne its a windowed app.
- SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE);
-
- // Install the Google Breakpad crash handler for Windows
- if(mExceptionHandler == 0)
- {
- mExceptionHandler = new google_breakpad::ExceptionHandler(
- std::wstring(mDumpPath.begin(),mDumpPath.end()), //Dump path
- clear_CrashLoggerReserve_callback,
- windows_post_minidump_callback,
- 0,
- google_breakpad::ExceptionHandler::HANDLER_ALL);
- if (mExceptionHandler)
- {
- mExceptionHandler->set_handle_debug_exceptions(true);
- }
- }
-#endif
-#else
+#if !LL_WINDOWS
//
// Start up signal handling.
//
// There are two different classes of signals. Synchronous signals are delivered to a specific
// thread, asynchronous signals can be delivered to any thread (in theory)
//
-
setup_signals();
-
- // Add google breakpad exception handler configured for Darwin/Linux.
- bool installHandler = true;
-#if LL_DARWIN
- // For the special case of Darwin, we do not want to install the handler if
- // the process is being debugged as the app will exit with value ABRT (6) if
- // we do. Unfortunately, the code below which performs that test relies on
- // the structure kinfo_proc which has been tagged by apple as an unstable
- // API. We disable this test for shipping versions to avoid conflicts with
- // future releases of Darwin. This test is really only needed for developers
- // starting the app from a debugger anyway.
- #ifndef LL_RELEASE_FOR_DOWNLOAD
- int mib[4];
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC;
- mib[2] = KERN_PROC_PID;
- mib[3] = getpid();
-
- struct kinfo_proc info;
- memset(&info, 0, sizeof(info));
-
- size_t size = sizeof(info);
- int result = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
- if((result == 0) || (errno == ENOMEM))
- {
- // P_TRACED flag is set, so this process is being debugged; do not install
- // the handler
- if(info.kp_proc.p_flag & P_TRACED) installHandler = false;
- }
- else
- {
- // Failed to discover if the process is being debugged; default to
- // installing the handler.
- installHandler = true;
- }
-
- if(installHandler && (mExceptionHandler == 0))
- {
- mExceptionHandler = new google_breakpad::ExceptionHandler(mDumpPath, clear_CrashLoggerReserve_callback, &unix_post_minidump_callback, 0, true, 0);
- }
- #endif
-#elif LL_LINUX
- if(installHandler && (mExceptionHandler == 0))
- {
- if (mDumpPath.empty())
- {
- mDumpPath = "/tmp";
- }
- google_breakpad::MinidumpDescriptor desc(mDumpPath);
- mExceptionHandler = new google_breakpad::ExceptionHandler(desc, clear_CrashLoggerReserve_callback, unix_minidump_callback, NULL, true, -1);
- }
-#endif
-
+#endif // ! LL_WINDOWS
+#if !defined(USE_CRASHPAD)
+ startErrorThread();
#endif
}
@@ -466,7 +345,6 @@ void LLApp::setErrorHandler(LLAppErrorHandler handler)
LLApp::sErrorHandler = handler;
}
-
// static
void LLApp::runErrorHandler()
{
@@ -479,7 +357,6 @@ void LLApp::runErrorHandler()
LLApp::setStopped();
}
-
// static
void LLApp::setStatus(EAppStatus status)
{
@@ -494,43 +371,12 @@ void LLApp::setError()
setStatus(APP_STATUS_ERROR);
}
-void LLApp::setMiniDumpDir(const std::string &path)
-{
- if (path.empty())
- {
- mDumpPath = "/tmp";
- }
- else
- {
- mDumpPath = path;
- }
-
- if(mExceptionHandler == 0) return;
-#ifdef LL_WINDOWS
- wchar_t buffer[MAX_MINDUMP_PATH_LENGTH];
- mbstowcs(buffer, mDumpPath.c_str(), MAX_MINDUMP_PATH_LENGTH);
- mExceptionHandler->set_dump_path(std::wstring(buffer));
-#elif LL_LINUX
- //google_breakpad::MinidumpDescriptor desc("/tmp"); //path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched.
- google_breakpad::MinidumpDescriptor desc(mDumpPath); //path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched.
- mExceptionHandler->set_minidump_descriptor(desc);
-#else
- mExceptionHandler->set_dump_path(mDumpPath);
-#endif
-}
-
void LLApp::setDebugFileNames(const std::string &path)
{
mStaticDebugFileName = path + "static_debug_info.log";
mDynamicDebugFileName = path + "dynamic_debug_info.log";
}
-void LLApp::writeMiniDump()
-{
- if(mExceptionHandler == 0) return;
- mExceptionHandler->WriteMinidump();
-}
-
// static
void LLApp::setQuitting()
{
@@ -585,13 +431,6 @@ bool LLApp::isExiting()
void LLApp::disableCrashlogger()
{
- // Disable Breakpad exception handler.
- if (mExceptionHandler != 0)
- {
- delete mExceptionHandler;
- mExceptionHandler = 0;
- }
-
sDisableCrashlogger = TRUE;
}
@@ -660,12 +499,6 @@ LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *except
ms_sleep(10);
}
- //
- // Generate a minidump if we can.
- //
- // TODO: This needs to be ported over form the viewer-specific
- // LLWinDebug class
-
//
// At this point, we always want to exit the app. There's no graceful
// recovery for an unhandled exception.
@@ -965,150 +798,4 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
}
}
}
-
-#if LL_LINUX
-bool unix_minidump_callback(const google_breakpad::MinidumpDescriptor& minidump_desc, void* context, bool succeeded)
-{
- // Copy minidump file path into fixed buffer in the app instance to avoid
- // heap allocations in a crash handler.
-
- // path format: /.dmp
-
- //HACK: *path points to the buffer in getMiniDumpFilename which has already allocated space
- //to avoid doing allocation during crash.
- char * path = LLApp::instance()->getMiniDumpFilename();
- int dir_path_len = strlen(path);
-
- // The path must not be truncated.
- S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH - dir_path_len;
-
- llassert( (remaining - strlen(minidump_desc.path())) > 5);
-
- path += dir_path_len;
-
- if (dir_path_len > 0 && path[-1] != '/')
- {
- *path++ = '/';
- --remaining;
- }
-
- strncpy(path, minidump_desc.path(), remaining);
-
- LL_INFOS() << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL;
- LLApp::runErrorHandler();
-
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- clear_signals();
- return false;
-#else
- return true;
-#endif
-
-}
-#endif
-
-
-bool unix_post_minidump_callback(const char *dump_dir,
- const char *minidump_id,
- void *context, bool succeeded)
-{
- // Copy minidump file path into fixed buffer in the app instance to avoid
- // heap allocations in a crash handler.
-
- // path format: /.dmp
- int dirPathLength = strlen(dump_dir);
- int idLength = strlen(minidump_id);
-
- // The path must not be truncated.
- llassert((dirPathLength + idLength + 5) <= LLApp::MAX_MINDUMP_PATH_LENGTH);
-
- char * path = LLApp::instance()->getMiniDumpFilename();
- S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH;
- strncpy(path, dump_dir, remaining);
- remaining -= dirPathLength;
- path += dirPathLength;
- if (remaining > 0 && dirPathLength > 0 && path[-1] != '/')
- {
- *path++ = '/';
- --remaining;
- }
- if (remaining > 0)
- {
- strncpy(path, minidump_id, remaining);
- remaining -= idLength;
- path += idLength;
- strncpy(path, ".dmp", remaining);
- }
-
- LL_INFOS() << "generated minidump: " << path << LL_ENDL;
- LLApp::runErrorHandler();
-
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- clear_signals();
- return false;
-#else
- return true;
-#endif
-}
#endif // !WINDOWS
-
-#ifdef LL_WINDOWS
-bool windows_post_minidump_callback(const wchar_t* dump_path,
- const wchar_t* minidump_id,
- void* context,
- EXCEPTION_POINTERS* exinfo,
- MDRawAssertionInfo* assertion,
- bool succeeded)
-{
- char * path = LLApp::instance()->getMiniDumpFilename();
- S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH;
- size_t bytesUsed;
-
- bytesUsed = wcstombs(path, dump_path, static_cast(remaining));
- remaining -= bytesUsed;
- path += bytesUsed;
- if(remaining > 0 && bytesUsed > 0 && path[-1] != '\\')
- {
- *path++ = '\\';
- --remaining;
- }
- if(remaining > 0)
- {
- bytesUsed = wcstombs(path, minidump_id, static_cast(remaining));
- remaining -= bytesUsed;
- path += bytesUsed;
- }
- if(remaining > 0)
- {
- strncpy(path, ".dmp", remaining);
- }
-
- LL_INFOS() << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL;
- // *NOTE:Mani - this code is stolen from LLApp, where its never actually used.
- //OSMessageBox("Attach Debugger Now", "Error", OSMB_OK);
- // *TODO: Translate the signals/exceptions into cross-platform stuff
- // Windows implementation
- LL_INFOS() << "Entering Windows Exception Handler..." << LL_ENDL;
-
- if (LLApp::isError())
- {
- LL_WARNS() << "Got another fatal signal while in the error handler, die now!" << LL_ENDL;
- }
-
- // Flag status to error, so thread_error starts its work
- LLApp::setError();
-
- // Block in the exception handler until the app has stopped
- // This is pretty sketchy, but appears to work just fine
- while (!LLApp::isStopped())
- {
- ms_sleep(10);
- }
-
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- return false;
-#else
- return true;
-#endif
-}
-#endif
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index aab871799..2a8fddfa2 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -60,10 +60,6 @@ public:
};
#endif
-namespace google_breakpad {
- class ExceptionHandler; // See exception_handler.h
-}
-
class LL_COMMON_API LLApp : public LLOptionInterface
{
friend class LLErrorThread;
@@ -233,22 +229,11 @@ public:
static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred.
//@}
- // the maximum length of the minidump filename returned by getMiniDumpFilename()
- static const U32 MAX_MINDUMP_PATH_LENGTH = 256;
-
- // change the directory where Breakpad minidump files are written to
- void setMiniDumpDir(const std::string &path);
void setDebugFileNames(const std::string &path);
- // Return the Google Breakpad minidump filename after a crash.
- char *getMiniDumpFilename() { return mMinidumpPath; }
std::string* getStaticDebugFile() { return &mStaticDebugFileName; }
std::string* getDynamicDebugFile() { return &mDynamicDebugFileName; }
- // Write out a Google Breakpad minidump file.
- void writeMiniDump();
-
-
#if !LL_WINDOWS
//
// Child process handling (Unix only for now)
@@ -281,8 +266,6 @@ protected:
static BOOL sDisableCrashlogger; // Let the OS handle crashes for us.
std::wstring mCrashReportPipeStr; //Name of pipe to use for crash reporting.
- std::string mDumpPath; //output path for google breakpad. Dependency workaround.
-
#if !LL_WINDOWS
static LLAtomicU32* sSigChildCount; // Number of SIGCHLDs received.
typedef std::map child_map; // Map key is a PID
@@ -290,16 +273,13 @@ protected:
static LLAppChildCallback sDefaultChildCallback;
#endif
- void startErrorThread();
-
/**
* @brief This method is called at the end, just prior to deinitializing curl.
*/
void stopErrorThread();
private:
- // Contains the filename of the minidump file after a crash.
- char mMinidumpPath[MAX_MINDUMP_PATH_LENGTH];
+ void startErrorThread();
std::string mStaticDebugFileName;
std::string mDynamicDebugFileName;
@@ -323,11 +303,8 @@ private:
std::vector mLiveFiles;
//@}
-private:
// the static application instance if it was created.
static LLApp* sApplication;
- google_breakpad::ExceptionHandler * mExceptionHandler;
-
#if !LL_WINDOWS
friend void default_unix_signal_handler(int signum, siginfo_t *info, void *);
diff --git a/indra/llmessage/aihttptimeoutpolicy.cpp b/indra/llmessage/aihttptimeoutpolicy.cpp
index 705b4770d..70e71c1d7 100644
--- a/indra/llmessage/aihttptimeoutpolicy.cpp
+++ b/indra/llmessage/aihttptimeoutpolicy.cpp
@@ -960,5 +960,4 @@ P(webProfileResponders);
P(wholeModelFeeResponder);
P(wholeModelUploadResponder);
P2(XMLRPCResponder, connect_40s);
-P2(crashLoggerResponder, transfer_300s);
P(getUpdateInfoResponder);
\ No newline at end of file
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index d8b2673b0..181d5cf46 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -12,6 +12,7 @@ include(BuildPackagesInfo)
include(BuildVersion)
include(BuildBranding)
include(CMakeCopyIfDifferent)
+include(CrashPad)
include(DBusGlib)
include(FMODSTUDIO)
include(GeneratePrecompiledHeader)
@@ -49,6 +50,11 @@ include(WinManifest)
include(ZLIB)
include(URIPARSER)
+
+if(USE_CRASHPAD)
+ include_directories(${CRASHPAD_INCLUDE_DIRS})
+endif(USE_CRASHPAD)
+
include_directories(
${STATEMACHINE_INCLUDE_DIRS}
${DBUSGLIB_INCLUDE_DIRS}
@@ -143,7 +149,6 @@ set(viewer_SOURCE_FILES
llconfirmationmanager.cpp
llconsole.cpp
llcontrolavatar.cpp
- llcrashlogger.cpp
llcurrencyuimanager.cpp
llcylinder.cpp
lldaycyclemanager.cpp
@@ -681,7 +686,6 @@ set(viewer_HEADER_FILES
llconfirmationmanager.h
llconsole.h
llcontrolavatar.h
- llcrashlogger.h
llcurrencyuimanager.h
llcylinder.h
lldaycyclemanager.h
@@ -1375,7 +1379,6 @@ set(viewer_APPSETTINGS_FILES
app_settings/settings.xml
app_settings/settings_ascent.xml
app_settings/settings_ascent_coa.xml
- app_settings/settings_crash_behavior.xml
app_settings/settings_files.xml
app_settings/settings_per_account.xml
app_settings/settings_sh.xml
@@ -1624,6 +1627,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
${PNG_PRELOAD_ARCHIVES}
${ZLIB_PRELOAD_ARCHIVES}
${GOOGLE_PERFTOOLS_LIBRARIES}
+ ${CRASHPAD_LIBRARIES}
${LLAUDIO_LIBRARIES}
${LLAUDIO_VORBIS_LIBRARIES}
${LLCHARACTER_LIBRARIES}
@@ -1823,8 +1827,10 @@ if (INSTALL)
include(${CMAKE_CURRENT_SOURCE_DIR}/ViewerInstall.cmake)
endif (INSTALL)
-if (PACKAGE)
+if (PACKAGE AND USE_CRASHPAD)
+ # Breakpad symbol-file generation
set(SYMBOL_NAME ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${VIEWER_CHANNEL_NOSPACE}-${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}-symbols)
+
set(SYMBOL_SEARCH_DIRS "")
if (WINDOWS)
list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
@@ -1854,7 +1860,6 @@ if (PACKAGE)
set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest)
endif (LINUX)
- if(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING)
if(GEN_IS_MULTI_CONFIG)
set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE})
else()
@@ -1875,14 +1880,14 @@ if (PACKAGE)
DEPENDS generate_breakpad_symbols.py
VERBATIM)
- add_custom_target(generate_breakpad_symbols DEPENDS "${VIEWER_SYMBOL_FILE}")
- add_dependencies(generate_breakpad_symbols ${VIEWER_BINARY_NAME})
-if(VIEWER_COPY_MANIFEST)
- add_dependencies(generate_breakpad_symbols ${VIEWER_COPY_MANIFEST})
-endif(VIEWER_COPY_MANIFEST)
- add_dependencies(llpackage generate_breakpad_symbols)
- endif(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING)
-endif (PACKAGE)
+ add_custom_target(generate_symbols DEPENDS "${VIEWER_SYMBOL_FILE}" ${VIEWER_BINARY_NAME} "${VIEWER_COPY_MANIFEST}")
+ add_dependencies(generate_symbols ${VIEWER_BINARY_NAME})
+ if (WINDOWS OR LINUX)
+ add_dependencies(generate_symbols "${VIEWER_COPY_MANIFEST}")
+ endif (WINDOWS OR LINUX)
+
+ add_dependencies(llpackage generate_symbols)
+endif ()
# Add tests
if (LL_TESTS)
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index b074c964b..e1ba77b93 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2538,17 +2538,6 @@ This should be as low as possible, but too low may break functionality
1
- CrashHostUrl
-
- Comment
- A URL pointing to a crash report handler; overrides cluster negotiation to locate crash handler.
- Persist
- 1
- Type
- String
- Value
- http://crash.singularityviewer.org/report.php>
-
AFKTimeout
Comment
@@ -18971,24 +18960,13 @@ This should be as low as possible, but too low may break functionality
CrashSubmitBehavior
Comment
- Controls behavior when viewer crashes (0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report)
+ Controls behavior when viewer crashes (0 = never send crash report, 1 = always send crash report)
Persist
1
Type
S32
Value
- 0
-
- CrashReportID
-
- Comment
- ID of the last crash report sent. Zero indicates that no crash report has been sent. Non-zero value can be useful infermation for developers to track a specific issue
- Persist
- 1
- Type
- S32
- Value
- 0
+ -1
EveryoneCopy
diff --git a/indra/newview/app_settings/settings_crash_behavior.xml b/indra/newview/app_settings/settings_crash_behavior.xml
deleted file mode 100644
index 74704f8ad..000000000
--- a/indra/newview/app_settings/settings_crash_behavior.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
- CrashSubmitBehavior
-
- Comment
- Controls behavior when viewer crashes (0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report)
- Persist
- 2
- Type
- S32
- Value
- 1
-
-
-
diff --git a/indra/newview/app_settings/settings_files.xml b/indra/newview/app_settings/settings_files.xml
index ac304f759..cfb4504f2 100644
--- a/indra/newview/app_settings/settings_files.xml
+++ b/indra/newview/app_settings/settings_files.xml
@@ -43,13 +43,6 @@
Requirement
1
- CrashSettings
-
- Name
- settings_crash_behavior.xml
- Requirement
- 1
-
User
@@ -65,11 +58,6 @@
NameFromSetting
ClientSettingsFile
- CrashSettings
-
- Name
- settings_crash_behavior.xml
-
Account
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index dcde01d9a..67d87861c 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -87,7 +87,6 @@
#include "llappearancemgr.h"
// [/SL:KB]
#include "llfloaterteleporthistory.h"
-#include "llcrashlogger.h"
#include "llweb.h"
#include "llsecondlifeurls.h"
#include "llavatarrenderinfoaccountant.h"
@@ -211,6 +210,20 @@
#include
+#ifdef USE_CRASHPAD
+#pragma warning(disable:4265)
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include "llnotificationsutil.h"
+#include "llversioninfo.h"
+#endif
+
////// Windows-specific includes to the bottom - nasty defines in these pollute the preprocessor
//
@@ -237,6 +250,8 @@ F32 gSimFrames;
BOOL gShowObjectUpdates = FALSE;
+S32 gLastExecDuration = -1; // (<0 indicates unknown)
+
BOOL gAcceptTOS = FALSE;
BOOL gAcceptCriticalMessage = FALSE;
@@ -297,8 +312,9 @@ BOOL gLogoutInProgress = FALSE;
////////////////////////////////////////////////////////////
// Internal globals... that should be removed.
static std::string gArgs;
-
+const int MAX_MARKER_LENGTH = 1024;
const std::string MARKER_FILE_NAME("Singularity.exec_marker");
+const std::string START_MARKER_FILE_NAME("Singularity.start_marker");;
const std::string ERROR_MARKER_FILE_NAME("Singularity.error_marker");
const std::string LLERROR_MARKER_FILE_NAME("Singularity.llerror_marker");
const std::string LOGOUT_MARKER_FILE_NAME("Singularity.logout_marker");
@@ -367,7 +383,6 @@ void init_default_trans_args()
const char *VFS_DATA_FILE_BASE = "data.db2.x.";
const char *VFS_INDEX_FILE_BASE = "index.db2.x.";
-static std::string gSecondLife;
std::string gWindowTitle;
std::string gLoginPage;
@@ -434,24 +449,6 @@ void request_initial_instant_messages()
}
}
-// A settings system callback for CrashSubmitBehavior
-bool handleCrashSubmitBehaviorChanged(const LLSD& newvalue)
-{
- S32 cb = newvalue.asInteger();
- const S32 NEVER_SUBMIT_REPORT = 2;
- if(cb == NEVER_SUBMIT_REPORT)
- {
-// LLWatchdog::getInstance()->cleanup(); // SJB: cleaning up a running watchdog thread is unsafe
- LLAppViewer::instance()->destroyMainloopTimeout();
- }
- else if(gSavedSettings.getBOOL("WatchdogEnabled") == TRUE)
- {
- // Don't re-enable the watchdog when we change the setting; this may get called before it's started
-// LLWatchdog::getInstance()->init();
- }
- return true;
-}
-
// Use these strictly for things that are constructed at startup,
// or for things that are performance critical. JC
static void settings_to_globals()
@@ -536,7 +533,6 @@ LLAppViewer* LLAppViewer::sInstance = NULL;
const std::string LLAppViewer::sGlobalSettingsName = "Global";
const std::string LLAppViewer::sPerAccountSettingsName = "PerAccount";
-const std::string LLAppViewer::sCrashSettingsName = "CrashSettings";
LLTextureCache* LLAppViewer::sTextureCache = NULL;
LLImageDecodeThread* LLAppViewer::sImageDecodeThread = NULL;
@@ -544,7 +540,7 @@ LLTextureFetch* LLAppViewer::sTextureFetch = NULL;
LLAppViewer::LLAppViewer() :
mMarkerFile(),
- mLogoutMarkerFile(NULL),
+ mLogoutMarkerFile(),
mReportedCrash(false),
mNumSessions(0),
mPurgeCache(false),
@@ -556,13 +552,11 @@ LLAppViewer::LLAppViewer() :
mMainloopTimeout(NULL),
mAgentRegionLastAlive(false)
{
- if(NULL != sInstance)
+ if(nullptr != sInstance)
{
LL_ERRS() << "Oh no! An instance of LLAppViewer already exists! LLAppViewer is sort of like a singleton." << LL_ENDL;
}
- mDumpPath.clear();
-
// Need to do this initialization before we do anything else, since anything
// that touches files should really go through the lldir API
{
@@ -580,7 +574,26 @@ LLAppViewer::LLAppViewer() :
gDirUtilp->initAppDirs("SecondLife", newview_path);
}
+ //
+ // IMPORTANT! Do NOT put anything that will write
+ // into the log files during normal startup until AFTER
+ // we run the "program crashed last time" error handler below.
+ //
sInstance = this;
+
+
+ initLoggingAndGetLastDuration();
+
+ processMarkerFiles();
+ //
+ // OK to write stuff to logs now, we've now crash reported if necessary
+ //
+#if !defined(USE_CRASHPAD)
+ // write dump files to a per-run dump directory to avoid multiple viewer issues.
+ std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "");
+
+ setDebugFileNames(logdir);
+#endif
}
@@ -589,13 +602,13 @@ LLAppViewer::~LLAppViewer()
destroyMainloopTimeout();
// If we got to this destructor somehow, the app didn't hang.
- removeMarkerFile();
+ removeMarkerFiles();
}
class LLUITranslationBridge : public LLTranslationBridge
{
public:
- virtual std::string getString(const std::string &xml_desc)
+ std::string getString(const std::string &xml_desc) override
{
return LLTrans::getString(xml_desc);
}
@@ -634,17 +647,151 @@ void fast_exit(int rc)
}
*/
+#ifdef USE_CRASHPAD
+base::FilePath databasePath()
+{
+ // Cache directory that will store crashpad information and minidumps
+ std::string crashpad_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "crashpad");
+ return base::FilePath(ll_convert_string_to_wide(crashpad_path));
+}
+
+static void handleCrashSubmitBehaviorChanged(LLControlVariable*, const LLSD& val)
+{
+ if (auto db = crashpad::CrashReportDatabase::Initialize(databasePath()))
+ {
+ if (auto settings = db->GetSettings())
+ {
+ settings->SetUploadsEnabled(val.asBoolean());
+ }
+ }
+}
+
+static void configureCrashUploads()
+{
+ auto database = databasePath();
+ auto db = crashpad::CrashReportDatabase::InitializeWithoutCreating(database);
+ if (!db) return;
+ auto settings = db->GetSettings();
+ if (!settings) return;
+ auto control = gSavedSettings.getControl("CrashSubmitBehavior");
+ control->getSignal()->connect(handleCrashSubmitBehaviorChanged);
+ if (control->get().asInteger() == -1)
+ {
+ LLNotificationsUtil::add("SubmitCrashReports", LLSD(), LLSD(), [control](const LLSD& p, const LLSD& f) {
+ control->set(!LLNotificationsUtil::getSelectedOption(p, f));
+ });
+ }
+
+ if (!settings->SetUploadsEnabled(control->get().asInteger() == 1))
+ {
+ LL_WARNS() << "Failed to set enable upload of crash database." << LL_ENDL;
+ }
+}
+#endif
+
+void LLAppViewer::initCrashReporting()
+{
+#ifdef USE_CRASHPAD
+ // Path to the out-of-process handler executable
+ std::string handler_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "crashpad_handler.exe");
+ if (!gDirUtilp->fileExists(handler_path))
+ {
+ LL_ERRS() << "Failed to initialize crashpad due to missing handler executable." << LL_ENDL;
+ return;
+ }
+ base::FilePath handler(ll_convert_string_to_wide(handler_path));
+
+ auto database = databasePath();
+
+ // URL used to submit minidumps to
+ std::string url(CRASHPAD_URL);
+
+ // Optional annotations passed via --annotations to the handler
+ std::map annotations;
+
+#if 0
+ unsigned char node_id[6];
+ if (LLUUID::getNodeID(node_id) > 0)
+ {
+ char md5str[MD5HEX_STR_SIZE] = { 0 };
+ LLMD5 hashed_unique_id;
+ hashed_unique_id.update(node_id, 6);
+ hashed_unique_id.finalize();
+ hashed_unique_id.hex_digest((char*)md5str);
+ annotations.emplace("sentry[contexts][app][device_app_hash]", std::string(md5str));
+ }
+#endif
+
+ annotations.emplace("sentry[contexts][app][app_name]", LLVersionInfo::getChannel());
+ annotations.emplace("sentry[contexts][app][app_version]", LLVersionInfo::getVersion());
+ annotations.emplace("sentry[contexts][app][app_build]", LLVersionInfo::getChannelAndVersion());
+
+ annotations.emplace("sentry[tags][second_instance]", fmt::to_string(isSecondInstance()));
+ //annotations.emplace("sentry[tags][bitness]", fmt::to_string(ADDRESS_SIZE));
+ annotations.emplace("sentry[tags][bitness]",
+#if defined(_WIN64) || defined(__x86_64__)
+ "64"
+#else
+ "32"
+#endif
+ );
+
+ // Optional arguments to pass to the handler
+ std::vector arguments;
+ arguments.push_back("--no-upload-gzip");
+ arguments.push_back("--no-rate-limit");
+ arguments.push_back("--monitor-self");
+
+ if (isSecondInstance())
+ {
+ arguments.push_back("--no-periodic-tasks");
+ }
+ else
+ {
+ auto db = crashpad::CrashReportDatabase::Initialize(database);
+ if (db == nullptr)
+ {
+ LL_WARNS() << "Failed to initialize crashpad database at path: " << wstring_to_utf8str(database.value()) << LL_ENDL;
+ return;
+ }
+
+ auto prune_condition = crashpad::PruneCondition::GetDefault();
+ if (prune_condition != nullptr)
+ {
+ auto ret = crashpad::PruneCrashReportDatabase(db.get(), prune_condition.get());
+ LL_INFOS() << "Pruned " << ret << " reports from the crashpad database." << LL_ENDL;
+ }
+ }
+
+ crashpad::CrashpadClient client;
+ bool success = client.StartHandler(
+ handler,
+ database,
+ database,
+ url,
+ annotations,
+ arguments,
+ /* restartable */ true,
+ /* asynchronous_start */ false
+ );
+ if (success)
+ LL_INFOS() << "Crashpad init success" << LL_ENDL;
+ else
+ LL_WARNS() << "FAILED TO INITIALIZE CRASHPAD" << LL_ENDL;
+#endif
+}
+
bool LLAppViewer::init()
-{
+{
+#ifdef USE_CRASHPAD
+ initCrashReporting();
+#endif
+
setupErrorHandling();
//
// Start of the application
//
- // IMPORTANT! Do NOT put anything that will write
- // into the log files during normal startup until AFTER
- // we run the "program crashed last time" error handler below.
- //
LLFastTimer::reset();
// initialize LLWearableType translation bridge.
@@ -667,15 +814,12 @@ bool LLAppViewer::init()
// this allows simple skinned file lookups to work
gDirUtilp->setSkinFolder("default", "en-us");
- initLogging();
+// initLoggingAndGetLastDuration();
//
// Curl must be initialized before any thread is running.
AICurlInterface::initCurl();
- // Logging is initialized. Now it's safe to start the error thread.
- startErrorThread();
-
//
// OK to write stuff to logs now, we've now crash reported if necessary
//
@@ -686,7 +830,6 @@ bool LLAppViewer::init()
LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ;
-
// initialize skinning util
LLSkinningUtil::initClass();
@@ -711,25 +854,9 @@ bool LLAppViewer::init()
AIHTTPTimeoutPolicy::setDefaultCurlTimeout(policy_tmp);
}
- // Check if we have a crash report to send
- LLCrashLogger crashLogger;
- crashLogger.checkCrashDump();
-
- // write Google Breakpad minidump files to a per-run dump directory to avoid multiple viewer issues.
- std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "");
- mDumpPath = logdir;
- setMiniDumpDir(logdir);
- logdir += gDirUtilp->getDirDelimiter();
- setDebugFileNames(logdir);
-
mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling"));
- {
- // Viewer metrics initialization
- //static LLCachedControl metrics_submode(gSavedSettings,
- // "QAModeMetrics",
- // false,
- // "Enables QA features (logging, faster cycling) for metrics collector");
+ {
if (gSavedSettings.getBOOL("QAModeMetrics"))
{
app_metrics_qa_mode = true;
@@ -782,6 +909,11 @@ bool LLAppViewer::init()
LLNotifications::instance().createDefaultChannels();
LL_INFOS("InitInfo") << "Notifications initialized." << LL_ENDL ;
+#ifdef USE_CRASHPAD
+ // Now that we have Settings and Notifications, we can configure crash uploads
+ configureCrashUploads();
+#endif
+
writeSystemInfo();
//////////////////////////////////////////////////////////////////////////////
@@ -797,10 +929,6 @@ bool LLAppViewer::init()
LL_INFOS("InitInfo") << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << LL_ENDL;
LL_INFOS("InitInfo") << "libcurl version is: " << LLCurl::getVersionString() << LL_ENDL;
- // Get the single value from the crash settings file, if it exists
- std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
- gCrashSettings.loadFromFile(crash_settings_filename);
-
/////////////////////////////////////////////////
// OS-specific login dialogs
/////////////////////////////////////////////////
@@ -898,6 +1026,7 @@ bool LLAppViewer::init()
if (!initCache())
{
+ LL_WARNS("InitInfo") << "Failed to init cache" << LL_ENDL;
std::ostringstream msg;
msg << LLTrans::getString("MBUnableToAccessFile");
OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK);
@@ -1051,9 +1180,8 @@ void LLAppViewer::initMaxHeapSize()
//currently SL is built under 32-bit setting, we set its max heap size no more than 1.6 GB.
//F32 max_heap_size_gb = llmin(1.6f, (F32)gSavedSettings.getF32("MaxHeapSize")) ;
-
F32Gigabytes max_heap_size_gb = (F32Gigabytes)gSavedSettings.getF32("MaxHeapSize") ;
-
+
//This is all a bunch of CRAP. We run LAA on windows. 64bit windows supports LAA out of the box. 32bit does not, unless PAE is on.
#if LL_WINDOWS
//http://msdn.microsoft.com/en-us/library/windows/desktop/ms684139%28v=vs.85%29.aspx
@@ -1081,7 +1209,7 @@ void LLAppViewer::initMaxHeapSize()
}
#endif
- BOOL enable_mem_failure_prevention = (BOOL)gSavedSettings.getBOOL("MemoryFailurePreventionEnabled") ;
+ BOOL enable_mem_failure_prevention = gSavedSettings.getBOOL("MemoryFailurePreventionEnabled") ;
LLMemory::initMaxHeapSizeGB(max_heap_size_gb, enable_mem_failure_prevention) ;
}
@@ -1263,7 +1391,6 @@ bool LLAppViewer::mainLoop()
gKeyboard->scanKeyboard();
if (gAgent.isCrouching())
gAgent.moveUp(-1);
-
}
// Update state based on messages, user input, object idle.
@@ -1311,11 +1438,11 @@ bool LLAppViewer::mainLoop()
pingMainloopTimeout("Main:Display");
gGLActive = TRUE;
display();
+
pingMainloopTimeout("Main:Snapshot");
LLFloaterSnapshot::update(); // take snapshots
gGLActive = FALSE;
}
-
}
pingMainloopTimeout("Main:Sleep");
@@ -1459,7 +1586,7 @@ bool LLAppViewer::mainLoop()
void LLAppViewer::flushVFSIO()
{
- while (1)
+ while (true)
{
S32 pending = LLVFSThread::updateClass(0);
pending += LLLFSThread::updateClass(0);
@@ -1477,7 +1604,8 @@ extern void cleanup_pose_stand(void);
bool LLAppViewer::cleanup()
{
//ditch LLVOAvatarSelf instance
- gAgentAvatarp = NULL;
+ gAgentAvatarp = nullptr;
+
// remove any old breakpad minidump files from the log directory
if (! isError())
@@ -1502,7 +1630,7 @@ bool LLAppViewer::cleanup()
release_start_screen(); // just in case
- LLError::logToFixedBuffer(NULL);
+ LLError::logToFixedBuffer(nullptr); // stop the fixed buffer recorder
LL_INFOS() << "Cleaning Up" << LL_ENDL;
@@ -1533,7 +1661,7 @@ bool LLAppViewer::cleanup()
}
delete gAssetStorage;
- gAssetStorage = NULL;
+ gAssetStorage = nullptr;
LLPolyMesh::freeAllMeshes();
@@ -1541,7 +1669,10 @@ bool LLAppViewer::cleanup()
// Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be deleted.
- LLWorldMap::getInstance()->reset(); // release any images
+ if (LLWorldMap::instanceExists())
+ {
+ LLWorldMap::getInstance()->reset(); // release any images
+ }
LLCalc::cleanUp();
@@ -1610,7 +1741,7 @@ bool LLAppViewer::cleanup()
// This may generate window reshape and activation events.
// Therefore must do this before destroying the message system.
delete gViewerWindow;
- gViewerWindow = NULL;
+ gViewerWindow = nullptr;
LL_INFOS() << "ViewerWindow deleted" << LL_ENDL;
}
@@ -1618,7 +1749,7 @@ bool LLAppViewer::cleanup()
// viewer UI relies on keyboard so keep it aound until viewer UI isa gone
delete gKeyboard;
- gKeyboard = NULL;
+ gKeyboard = nullptr;
LL_INFOS() << "Cleaning up Objects" << LL_ENDL;
@@ -1695,10 +1826,6 @@ bool LLAppViewer::cleanup()
LL_INFOS() << "Saved settings" << LL_ENDL;
}
- std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
- // save all settings, even if equals defaults
- gCrashSettings.saveToFile(crash_settings_filename, FALSE);
-
// Save URL history file
LLURLHistory::saveFile("url_history.xml");
@@ -1712,15 +1839,15 @@ bool LLAppViewer::cleanup()
// save mute list. gMuteList used to also be deleted here too.
LLMuteList::getInstance()->cache(gAgent.getID());
+
if (mPurgeOnExit)
{
LL_INFOS() << "Purging all cache files on exit" << LL_ENDL;
gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),"*.*");
}
- removeMarkerFile(); // Any crashes from here on we'll just have to ignore
// moved this stuff from above to make it conditional here...
- if(!anotherInstanceRunning())
+ if(!mSecondInstance)
{
removeCacheFiles("*.wav");
removeCacheFiles("*.tmp");
@@ -1736,8 +1863,7 @@ bool LLAppViewer::cleanup()
LL_INFOS() << "Not removing cache files. Other viewer instance detected." << LL_ENDL;
}
//
-
- removeDumpDir();
+
writeDebugInfo();
// Stop the plugin read thread if it's running.
@@ -1751,7 +1877,7 @@ bool LLAppViewer::cleanup()
LLTimer idleTimer;
idleTimer.reset();
const F64 max_idle_time = 5.f; // 5 seconds
- while(1)
+ while(true)
{
S32 pending = 0;
pending += LLAppViewer::getTextureCache()->update(1); // unpauses the worker thread
@@ -1761,7 +1887,7 @@ bool LLAppViewer::cleanup()
pending += LLLFSThread::updateClass(0);
if (!pending)
{
- break;
+ break ; //done
}
else if (idleTimer.getElapsedTimeF64() >= max_idle_time)
{
@@ -1775,14 +1901,16 @@ bool LLAppViewer::cleanup()
sTextureFetch->shutdown();
sTextureCache->shutdown();
sImageDecodeThread->shutdown();
+
sTextureFetch->shutDownTextureCacheThread();
sTextureFetch->shutDownImageDecodeThread();
delete sTextureCache;
- sTextureCache = NULL;
+ sTextureCache = nullptr;
delete sTextureFetch;
- sTextureFetch = NULL;
+ sTextureFetch = nullptr;
delete sImageDecodeThread;
- sImageDecodeThread = NULL;
+ sImageDecodeThread = nullptr;
+
LL_INFOS() << "Cleaning up Media and Textures" << LL_ENDL;
@@ -1815,9 +1943,9 @@ bool LLAppViewer::cleanup()
// For safety, the LLVFS has to be deleted *after* LLVFSThread. This should be cleaned up.
// (LLVFS doesn't know about LLVFSThread so can't kill pending requests) -Steve
delete gStaticVFS;
- gStaticVFS = NULL;
+ gStaticVFS = nullptr;
delete gVFS;
- gVFS = NULL;
+ gVFS = nullptr;
LLWatchdog::getInstance()->cleanup();
@@ -1832,7 +1960,6 @@ bool LLAppViewer::cleanup()
// Cleanup settings last in case other classes reference them.
gSavedSettings.cleanup();
gColors.cleanup();
- gCrashSettings.cleanup();
LLViewerAssetStatsFF::cleanup();
// If we're exiting to launch an URL, do that here so the screen
@@ -1842,7 +1969,7 @@ bool LLAppViewer::cleanup()
LL_INFOS() << "Launch file on quit." << LL_ENDL;
#if LL_WINDOWS
// Indicate an application is starting.
- SetCursor(LoadCursor(NULL, IDC_WAIT));
+ SetCursor(LoadCursor(nullptr, IDC_WAIT));
#endif
// HACK: Attempt to wait until the screen res. switch is complete.
@@ -1863,6 +1990,8 @@ bool LLAppViewer::cleanup()
LLError::LLCallStacks::cleanup();
+ removeMarkerFiles();
+
MEM_TRACK_RELEASE
LL_INFOS() << "Goodbye!" << LL_ENDL;
@@ -1871,13 +2000,13 @@ bool LLAppViewer::cleanup()
return true;
}
-// A callback for llerrs to call during the watchdog error.
+// A callback for LL_ERRS() to call during the watchdog error.
void watchdog_llerrs_callback(const std::string &error_string)
{
gLLErrorActivated = true;
#ifdef LL_WINDOWS
- RaiseException(0,0,0,0);
+ RaiseException(0,0,0,nullptr);
#else
raise(SIGQUIT);
#endif
@@ -1898,9 +2027,8 @@ bool LLAppViewer::initThreads()
static const bool enable_threads = true;
#endif
- const S32 NEVER_SUBMIT_REPORT = 2;
bool use_watchdog = gSavedSettings.getBOOL("WatchdogEnabled");
- bool send_reports = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING) != NEVER_SUBMIT_REPORT;
+ bool send_reports = gSavedSettings.getS32("CrashSubmitBehavior") == 1;
if(use_watchdog && send_reports)
{
LLWatchdog::getInstance()->init(watchdog_killer_callback);
@@ -1937,8 +2065,8 @@ void errorCallback(const std::string &error_string)
static std::string last_message;
if(last_message != error_string)
{
- U32 response = OSMessageBox(error_string, "Crash Loop?", OSMB_YESNO);
- if(response)
+ U32 response = OSMessageBox(error_string, LLTrans::getString("MBFatalError"), OSMB_YESNO);
+ if (response == OSBTN_NO)
{
last_message = error_string;
return;
@@ -1947,38 +2075,91 @@ void errorCallback(const std::string &error_string)
//Set the ErrorActivated global so we know to create a marker file
gLLErrorActivated = true;
+ gDebugInfo["FatalMessage"] = error_string;
+ // We're not already crashing -- we simply *intend* to crash. Since we
+ // haven't actually trashed anything yet, we can afford to write the whole
+ // static info file.
+ LLAppViewer::instance()->writeDebugInfo();
+
LLError::crashAndLoop(error_string);
}
}
-bool init_logging();
-bool LLAppViewer::initLogging()
+void LLAppViewer::initLoggingAndGetLastDuration()
{
//
// Set up logging defaults for the viewer
//
LLError::initForApplication(
- gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
+ gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")
+ );
LLError::setFatalFunction(errorCallback);
+ //LLError::setTimeFunction(getRuntime);
- return init_logging();
+ initLoggingInternal();
}
-bool init_logging()
+void LLAppViewer::initLoggingInternal()
{
// Remove the last ".old" log file.
- std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, OLD_LOG_FILE);
+ std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
+ OLD_LOG_FILE);
LLFile::remove(old_log_file);
+ // Get name of the log file
+ std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
+ LOG_FILE);
+ /*
+ * Before touching any log files, compute the duration of the last run
+ * by comparing the ctime of the previous start marker file with the ctime
+ * of the last log file.
+ */
+ std::string start_marker_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, START_MARKER_FILE_NAME);
+ llstat start_marker_stat;
+ llstat log_file_stat;
+ std::ostringstream duration_log_stream; // can't log yet, so save any message for when we can below
+ int start_stat_result = LLFile::stat(start_marker_file_name, &start_marker_stat);
+ int log_stat_result = LLFile::stat(log_file, &log_file_stat);
+ if ( 0 == start_stat_result && 0 == log_stat_result )
+ {
+ int elapsed_seconds = log_file_stat.st_ctime - start_marker_stat.st_ctime;
+ // only report a last run time if the last viewer was the same version
+ // because this stat will be counted against this version
+ if ( markerIsSameVersion(start_marker_file_name) )
+ {
+ gLastExecDuration = elapsed_seconds;
+ }
+ else
+ {
+ duration_log_stream << "start marker from some other version; duration is not reported";
+ gLastExecDuration = -1;
+ }
+ }
+ else
+ {
+ // at least one of the LLFile::stat calls failed, so we can't compute the run time
+ duration_log_stream << "duration stat failure; start: "<< start_stat_result << " log: " << log_stat_result;
+ gLastExecDuration = -1; // unknown
+ }
+ std::string duration_log_msg(duration_log_stream.str());
+
+ // Create a new start marker file for comparison with log file time for the next run
+ LLAPRFile start_marker_file ;
+ start_marker_file.open(start_marker_file_name, LL_APR_WB);
+ if (start_marker_file.getFileHandle())
+ {
+ recordMarkerVersion(start_marker_file);
+ start_marker_file.close();
+ }
+
// Rename current log file to ".old"
- std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOG_FILE);
LLFile::rename(log_file, old_log_file);
- // Set the log file to Singularity.log
-
+ // Set the log file to SecondLife.log
LLError::logToFile(log_file);
-
- // *FIX:Mani no error handling here!
- return true;
+ if (!duration_log_msg.empty())
+ {
+ LL_WARNS("MarkerFile") << duration_log_msg << LL_ENDL;
+ }
}
bool LLAppViewer::loadSettingsFromDirectory(AIReadAccess const& settings_r,
@@ -2098,7 +2279,6 @@ bool LLAppViewer::initConfiguration()
//Set up internal pointers
settings[sGlobalSettingsName] = &gSavedSettings;
settings[sPerAccountSettingsName] = &gSavedPerAccountSettings;
- settings[sCrashSettingsName] = &gCrashSettings;
//Load settings files list
std::string settings_file_list = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_files.xml");
@@ -2125,9 +2305,9 @@ bool LLAppViewer::initConfiguration()
bool set_defaults = true;
if(!loadSettingsFromDirectory(settings_w, "Default", set_defaults))
{
- std::ostringstream msg;
- msg << "Unable to load default settings file. The installation may be corrupted.";
- OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK);
+ OSMessageBox(
+ "Unable to load default settings file. The installation may be corrupted.",
+ LLStringUtil::null,OSMB_OK);
return false;
}
@@ -2139,6 +2319,7 @@ bool LLAppViewer::initConfiguration()
gSavedSettings.connectCOAVars(gSavedPerAccountSettings);
// - set procedural settings
+ // Note: can't use LL_PATH_PER_SL_ACCOUNT for any of these since we haven't logged in yet
gSavedSettings.setString("ClientSettingsFile",
gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Global")));
@@ -2171,8 +2352,6 @@ bool LLAppViewer::initConfiguration()
gSavedSettings.setBOOL("WatchdogEnabled", FALSE);
#endif
- gCrashSettings.getControl(CRASH_BEHAVIOR_SETTING)->getSignal()->connect(boost::bind(&handleCrashSubmitBehaviorChanged, _2));
-
// These are warnings that appear on the first experience of that condition.
// They are already set in the settings_default.xml file, but still need to be added to LLFirstUse
// for disable/reset ability
@@ -2231,7 +2410,7 @@ bool LLAppViewer::initConfiguration()
const std::string log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOG_FILE);
LL_INFOS() << "Attempting to use portable settings and cache!" << LL_ENDL;
gDirUtilp->makePortable();
- init_logging(); // Switch to portable log file
+ initLoggingInternal(); // Switch to portable log file
LL_INFOS() << "Portable viewer configuration initialized!" << LL_ENDL;
LLFile::remove(log);
LL_INFOS() << "Cleaned up local log file to keep this computer untouched." << LL_ENDL;
@@ -2246,7 +2425,7 @@ bool LLAppViewer::initConfiguration()
gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
clp.getOption("settings")[0]);
gSavedSettings.setString("ClientSettingsFile", user_settings_filename);
- LL_INFOS() << "Using command line specified settings filename: "
+ LL_INFOS("Settings") << "Using command line specified settings filename: "
<< user_settings_filename << LL_ENDL;
}
else
@@ -2289,7 +2468,7 @@ bool LLAppViewer::initConfiguration()
if(clp.hasOption("disablecrashlogger"))
{
LL_WARNS() << "Crashes will be handled by system, stack trace logs and crash logger are both disabled" <disableCrashlogger();
+ disableCrashlogger();
}
// Handle initialization from settings.
@@ -2306,7 +2485,7 @@ bool LLAppViewer::initConfiguration()
LL_INFOS() << msg.str() << LL_ENDL;
OSMessageBox(
- msg.str().c_str(),
+ msg.str(),
LLStringUtil::null,
OSMB_OK);
@@ -2406,22 +2585,6 @@ bool LLAppViewer::initConfiguration()
gSavedSettings.getString("Language"));
}
- // XUI:translate
- gSecondLife = LLTrans::getString("APP_NAME");
-
- // Read skin/branding settings if specified.
- //if (! gDirUtilp->getSkinDir().empty() )
- //{
- // std::string skin_def_file = gDirUtilp->findSkinnedFilename("skin.xml");
- // LLXmlTree skin_def_tree;
-
- // if (!skin_def_tree.parseFile(skin_def_file))
- // {
- // LL_ERRS() << "Failed to parse skin definition." << LL_ENDL;
- // }
-
- //}
-
#if LL_DARWIN
// Initialize apple menubar and various callbacks
init_apple_menu(LLTrans::getString("APP_NAME").c_str());
@@ -2469,46 +2632,29 @@ bool LLAppViewer::initConfiguration()
}
}
- if (!gSavedSettings.getBOOL("AllowMultipleViewers"))
+
+ //
+ // Check for another instance of the app running
+ //
+ if (mSecondInstance && !gSavedSettings.getBOOL("AllowMultipleViewers"))
{
- //
- // Check for another instance of the app running
- //
-
- mSecondInstance = anotherInstanceRunning();
-
- if (mSecondInstance)
- {
- std::ostringstream msg;
- msg << LLTrans::getString("MBAlreadyRunning");
- OSMessageBox(
- msg.str(),
- LLStringUtil::null,
- OSMB_OK);
- return false;
- }
-
- initMarkerFile();
-
+ OSMessageBox(
+ LLTrans::getString("MBAlreadyRunning"),
+ LLStringUtil::null,
+ OSMB_OK);
+ return false;
}
- else
- {
- mSecondInstance = anotherInstanceRunning();
-
- if (mSecondInstance)
- {
- // This is the second instance of SL. Turn off voice support,
- // but make sure the setting is *not* persisted.
- LLControlVariable* disable_voice = gSavedSettings.getControl("CmdLineDisableVoice");
- if(disable_voice && !gSavedSettings.getBOOL("VoiceMultiInstance"))
- {
- const BOOL DO_NOT_PERSIST = FALSE;
- disable_voice->setValue(LLSD(TRUE), DO_NOT_PERSIST);
- }
- }
- initMarkerFile();
-
+ if (mSecondInstance)
+ {
+ // This is the second instance of SL. Turn off voice support,
+ // but make sure the setting is *not* persisted.
+ LLControlVariable* disable_voice = gSavedSettings.getControl("CmdLineDisableVoice");
+ if(disable_voice && !gSavedSettings.getBOOL("VoiceMultiInstance"))
+ {
+ const BOOL DO_NOT_PERSIST = FALSE;
+ disable_voice->setValue(LLSD(TRUE), DO_NOT_PERSIST);
+ }
}
// need to do this here - need to have initialized global settings first
@@ -2592,25 +2738,25 @@ bool LLAppViewer::initWindow()
//gViewerWindow->getWindow()->show();
LL_INFOS("AppInit") << "Window initialization done." << LL_ENDL;
+
return true;
}
void LLAppViewer::writeDebugInfo(bool isStatic)
{
+#if !defined(USE_CRASHPAD)
//Try to do the minimum when writing data during a crash.
std::string* debug_filename;
debug_filename = ( isStatic
? getStaticDebugFile()
: getDynamicDebugFile() );
- LL_INFOS() << "Opening debug file " << *debug_filename << LL_ENDL;
- llofstream out_file(*debug_filename);
+ LL_INFOS() << "Writing debug file " << *debug_filename << LL_ENDL;
+ llofstream out_file(debug_filename->c_str());
isStatic ? LLSDSerialize::toPrettyXML(gDebugInfo, out_file)
: LLSDSerialize::toPrettyXML(gDebugInfo["Dynamic"], out_file);
-
-
- out_file.close();
+#endif
}
void LLAppViewer::cleanupSavedSettings()
@@ -2673,12 +2819,13 @@ void LLAppViewer::writeSystemInfo()
gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor();
gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch();
gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::getBuild();
-
+ gDebugInfo["ClientInfo"]["AddressSize"] =
#if defined(_WIN64) || defined(__x86_64__)
- gDebugInfo["ClientInfo"]["Architecture"] = "x86_64";
+ "64";
#else
- gDebugInfo["ClientInfo"]["Architecture"] = "i386";
+ "32";
#endif
+
gDebugInfo["CAFilename"] = gDirUtilp->getCAFile();
gDebugInfo["CPUInfo"]["CPUString"] = gSysCPU.getCPUString();
@@ -2742,9 +2889,9 @@ void LLAppViewer::writeSystemInfo()
void LLAppViewer::handleViewerCrash()
{
- LL_INFOS() << "Handle viewer crash entry." << LL_ENDL;
+ LL_INFOS("CRASHREPORT") << "Handle viewer crash entry." << LL_ENDL;
- LL_INFOS() << "Last render pool type: " << LLPipeline::sCurRenderPoolType << LL_ENDL ;
+ LL_INFOS("CRASHREPORT") << "Last render pool type: " << LLPipeline::sCurRenderPoolType << LL_ENDL ;
LLMemory::logMemoryInfo(true) ;
@@ -2787,8 +2934,7 @@ void LLAppViewer::handleViewerCrash()
{
gDebugInfo["Dynamic"]["ParcelMediaURL"] = parcel->getMediaURL();
}
-
-
+
gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile");
gDebugInfo["CAFilename"] = gDirUtilp->getCAFile();
gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName();
@@ -2805,7 +2951,7 @@ void LLAppViewer::handleViewerCrash()
}
else
{
- gDebugInfo["LastExecEvent"] = gLLErrorActivated ? LAST_EXEC_LLERROR_CRASH : LAST_EXEC_OTHER_CRASH;
+ gDebugInfo["Dynamic"]["LastExecEvent"] = gLLErrorActivated ? LAST_EXEC_LLERROR_CRASH : LAST_EXEC_OTHER_CRASH;
}
if(gAgent.getRegion())
@@ -2833,26 +2979,27 @@ void LLAppViewer::handleViewerCrash()
//we're already in a crash situation
if (gDirUtilp)
{
- std::string crash_file_name;
- if(gLLErrorActivated) crash_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LLERROR_MARKER_FILE_NAME);
- else crash_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,ERROR_MARKER_FILE_NAME);
- LL_INFOS() << "Creating crash marker file " << crash_file_name << LL_ENDL;
-
- LLAPRFile crash_file(crash_file_name, LL_APR_W);
- if (crash_file.getFileHandle())
+ std::string crash_marker_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
+ gLLErrorActivated
+ ? LLERROR_MARKER_FILE_NAME
+ : ERROR_MARKER_FILE_NAME);
+ LLAPRFile crash_marker_file ;
+ crash_marker_file.open(crash_marker_file_name, LL_APR_WB);
+ if (crash_marker_file.getFileHandle())
{
- LL_INFOS("MarkerFile") << "Created crash marker file " << crash_file_name << LL_ENDL;
+ LL_INFOS("MarkerFile") << "Created crash marker file " << crash_marker_file_name << LL_ENDL;
+ recordMarkerVersion(crash_marker_file);
}
else
{
- LL_WARNS("MarkerFile") << "Cannot create error marker file " << crash_file_name << LL_ENDL;
+ LL_WARNS("MarkerFile") << "Cannot create error marker file " << crash_marker_file_name << LL_ENDL;
}
}
- char *minidump_file = pApp->getMiniDumpFilename();
- if(minidump_file && minidump_file[0] != 0)
+ else
{
- gDebugInfo["Dynamic"]["MinidumpPath"] = minidump_file;
+ LL_WARNS("MarkerFile") << "No gDirUtilp with which to create error marker file name" << LL_ENDL;
}
+ LL_WARNS("CRASHREPORT") << "no minidump file? ah yeah, boi!" << LL_ENDL;
gDebugInfo["Dynamic"]["CrashType"]="crash";
@@ -2860,13 +3007,17 @@ void LLAppViewer::handleViewerCrash()
{
std::string filename;
filename = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "stats.log");
- llofstream file(filename, llofstream::binary);
+ LL_DEBUGS("CRASHREPORT") << "recording stats " << filename << LL_ENDL;
+ llofstream file(filename.c_str(), std::ios_base::binary);
if(file.good())
{
- LL_INFOS() << "Handle viewer crash generating stats log." << LL_ENDL;
gMessageSystem->summarizeLogs(file);
file.close();
}
+ else
+ {
+ LL_WARNS("CRASHREPORT") << "problem recording stats" << LL_ENDL;
+ }
}
if (gMessageSystem)
@@ -2879,158 +3030,241 @@ void LLAppViewer::handleViewerCrash()
// Close the debug file
pApp->writeDebugInfo(false); //false answers the isStatic question with the least overhead.
-
- LLError::logToFile("");
-
- // Remove the marker file, since otherwise we'll spawn a process that'll keep it locked
- if(gDebugInfo["Dynamic"]["LastExecEvent"].asInteger() == LAST_EXEC_LOGOUT_CRASH)
- {
- pApp->removeMarkerFile(true);
- }
- else
- {
- pApp->removeMarkerFile(false);
- }
-
- return;
}
-bool LLAppViewer::anotherInstanceRunning()
+// static
+void LLAppViewer::recordMarkerVersion(LLAPRFile& marker_file)
{
- // We create a marker file when the program starts and remove the file when it finishes.
- // If the file is currently locked, that means another process is already running.
-
- std::string marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, MARKER_FILE_NAME);
- LL_DEBUGS("MarkerFile") << "Checking marker file for lock..." << LL_ENDL;
-
- //Freeze case checks
- if (LLAPRFile::isExist(marker_file, LL_APR_RB))
+ std::string marker_version(LLVersionInfo::getChannelAndVersion());
+ if ( marker_version.length() > MAX_MARKER_LENGTH )
{
- // File exists, try opening with write permissions
- LLAPRFile outfile(marker_file, LL_APR_WB);
- apr_file_t* fMarker = outfile.getFileHandle() ;
- if (!fMarker)
- {
- // Another instance is running. Skip the rest of these operations.
- LL_INFOS("MarkerFile") << "Marker file is locked." << LL_ENDL;
- return true;
- }
- if (apr_file_lock(fMarker, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) //flock(fileno(fMarker), LOCK_EX | LOCK_NB) == -1)
- {
- LL_INFOS("MarkerFile") << "Marker file is locked." << LL_ENDL;
- return true;
- }
- // No other instances; we'll lock this file now & delete on quit.
+ LL_WARNS_ONCE("MarkerFile") << "Version length ("<< marker_version.length()<< ")"
+ << " greater than maximum (" << MAX_MARKER_LENGTH << ")"
+ << ": marker matching may be incorrect"
+ << LL_ENDL;
}
- LL_DEBUGS("MarkerFile") << "Marker file isn't locked." << LL_ENDL;
- return false;
+
+ // record the viewer version in the marker file
+ marker_file.write(marker_version.data(), marker_version.length());
}
-void LLAppViewer::initMarkerFile()
+bool LLAppViewer::markerIsSameVersion(const std::string& marker_name) const
{
- //First, check for the existence of other files.
- //There are marker files for two different types of crashes
-
- mMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,MARKER_FILE_NAME);
- LL_DEBUGS("MarkerFile") << "Checking marker file for lock..." << LL_ENDL;
+ bool sameVersion = false;
+ std::string my_version(LLVersionInfo::getChannelAndVersion());
+ char marker_version[MAX_MARKER_LENGTH];
+
+ LLAPRFile marker_file;
+ marker_file.open(marker_name, LL_APR_RB);
+ if (marker_file.getFileHandle())
+ {
+ S32 marker_version_length = marker_file.read(marker_version, sizeof(marker_version));
+ std::string marker_string(marker_version, marker_version_length);
+ if ( 0 == my_version.compare( 0, my_version.length(), marker_version, 0, marker_version_length ) )
+ {
+ sameVersion = true;
+ }
+ LL_DEBUGS("MarkerFile") << "Compare markers for '" << marker_name << "': "
+ << "\n mine '" << my_version << "'"
+ << "\n marker '" << marker_string << "'"
+ << "\n " << ( sameVersion ? "same" : "different" ) << " version"
+ << LL_ENDL;
+ marker_file.close();
+ }
+ return sameVersion;
+}
+
+void LLAppViewer::processMarkerFiles()
+{
//We've got 4 things to test for here
- // - Other Process Running (Singularity.exec_marker present, locked)
- // - Freeze (Singularity.exec_marker present, not locked)
- // - LLError Crash (Singularity.llerror_marker present)
- // - Other Crash (Singularity.error_marker present)
+ // - Other Process Running (SecondLife.exec_marker present, locked)
+ // - Freeze (SecondLife.exec_marker present, not locked)
+ // - LLError Crash (SecondLife.llerror_marker present)
+ // - Other Crash (SecondLife.error_marker present)
// These checks should also remove these files for the last 2 cases if they currently exist
- //LLError/Error checks. Only one of these should ever happen at a time.
- std::string logout_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOGOUT_MARKER_FILE_NAME);
- std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME);
- std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME);
+ bool marker_is_same_version = true;
+ // first, look for the marker created at startup and deleted on a clean exit
+ mMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,MARKER_FILE_NAME);
+ if (LLAPRFile::isExist(mMarkerFileName, LL_APR_RB))
+ {
+ // File exists...
+ // first, read it to see if it was created by the same version (we need this later)
+ marker_is_same_version = markerIsSameVersion(mMarkerFileName);
- if (LLAPRFile::isExist(mMarkerFileName, LL_APR_RB) && !anotherInstanceRunning())
- {
- gLastExecEvent = LAST_EXEC_FROZE;
- LL_INFOS("MarkerFile") << "Exec marker found: program froze on previous execution" << LL_ENDL;
- }
- if(LLAPRFile::isExist(logout_marker_file, LL_APR_RB))
- {
- gLastExecEvent = LAST_EXEC_LOGOUT_FROZE;
- LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
- LLAPRFile::remove(logout_marker_file);
- }
- if(LLAPRFile::isExist(llerror_marker_file, LL_APR_RB))
- {
- LL_INFOS() << "Last exec LLError crashed, setting LastExecEvent to " << LAST_EXEC_LLERROR_CRASH << LL_ENDL;
- if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
- else gLastExecEvent = LAST_EXEC_LLERROR_CRASH;
- LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
- LLAPRFile::remove(llerror_marker_file);
- }
- if(LLAPRFile::isExist(error_marker_file, LL_APR_RB))
- {
- LL_INFOS("MarkerFile") << "Last exec crashed, setting LastExecEvent to " << LAST_EXEC_OTHER_CRASH << LL_ENDL;
- if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
- else gLastExecEvent = LAST_EXEC_OTHER_CRASH;
- LL_INFOS("MarkerFile") << "Last exec crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
- LLAPRFile::remove(error_marker_file);
- }
-
- // No new markers if another instance is running.
- if(anotherInstanceRunning())
- {
- return;
- }
-
- // Create the marker file for this execution & lock it
- apr_status_t s;
- s = mMarkerFile.open(mMarkerFileName, LL_APR_W, LLAPRFile::long_lived);
-
- if (s == APR_SUCCESS && mMarkerFile.getFileHandle())
- {
- LL_DEBUGS("MarkerFile") << "Marker file created." << LL_ENDL;
- }
- else
- {
- LL_INFOS("MarkerFile") << "Failed to create marker file." << LL_ENDL;
- return;
- }
- if (apr_file_lock(mMarkerFile.getFileHandle(), APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS)
- {
- mMarkerFile.close() ;
- LL_INFOS("MarkerFile") << "Marker file cannot be locked." << LL_ENDL;
- return;
- }
-
- LL_DEBUGS("MarkerFile") << "Marker file locked." << LL_ENDL;
-}
-
-void LLAppViewer::removeMarkerFile(bool leave_logout_marker)
-{
- LL_DEBUGS("MarkerFile") << "removeMarkerFile()" << LL_ENDL;
- if (mMarkerFile.getFileHandle())
- {
- mMarkerFile.close() ;
- LLAPRFile::remove( mMarkerFileName );
- }
- if (mLogoutMarkerFile != NULL)
- {
- if(!leave_logout_marker)
+ // now test to see if this file is locked by a running process (try to open for write)
+ LL_DEBUGS("MarkerFile") << "Checking exec marker file for lock..." << LL_ENDL;
+ mMarkerFile.open(mMarkerFileName, LL_APR_WB);
+ apr_file_t* fMarker = mMarkerFile.getFileHandle() ;
+ if (!fMarker)
{
- LLAPRFile::remove( mLogoutMarkerFileName );
- mLogoutMarkerFile = NULL;
+ LL_INFOS("MarkerFile") << "Exec marker file open failed - assume it is locked." << LL_ENDL;
+ mSecondInstance = true; // lock means that instance is running.
}
else
{
- LL_WARNS("MarkerFile") << "leaving markers because this is a second instance" << LL_ENDL;
+ // We were able to open it, now try to lock it ourselves...
+ if (apr_file_lock(fMarker, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS)
+ {
+ LL_WARNS_ONCE("MarkerFile") << "Locking exec marker failed." << LL_ENDL;
+ mSecondInstance = true; // lost a race? be conservative
+ }
+ else
+ {
+ // No other instances; we've locked this file now, so record our version; delete on quit.
+ recordMarkerVersion(mMarkerFile);
+ LL_DEBUGS("MarkerFile") << "Exec marker file existed but was not locked; rewritten." << LL_ENDL;
+ }
}
+
+ if (mSecondInstance)
+ {
+ LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' owned by another instance" << LL_ENDL;
+ }
+ else if (marker_is_same_version)
+ {
+ // the file existed, is ours, and matched our version, so we can report on what it says
+ LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found; last exec FROZE" << LL_ENDL;
+ gLastExecEvent = LAST_EXEC_FROZE;
+
+ }
+ else
+ {
+ LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found, but versions did not match" << LL_ENDL;
+ }
+ }
+ else // marker did not exist... last exec (if any) did not freeze
+ {
+ // Create the marker file for this execution & lock it; it will be deleted on a clean exit
+ apr_status_t s;
+ s = mMarkerFile.open(mMarkerFileName, LL_APR_WB, TRUE);
+
+ if (s == APR_SUCCESS && mMarkerFile.getFileHandle())
+ {
+ LL_DEBUGS("MarkerFile") << "Exec marker file '"<< mMarkerFileName << "' created." << LL_ENDL;
+ if (APR_SUCCESS == apr_file_lock(mMarkerFile.getFileHandle(), APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE))
+ {
+ recordMarkerVersion(mMarkerFile);
+ LL_DEBUGS("MarkerFile") << "Exec marker file locked." << LL_ENDL;
+ }
+ else
+ {
+ LL_WARNS("MarkerFile") << "Exec marker file cannot be locked." << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_WARNS("MarkerFile") << "Failed to create exec marker file '"<< mMarkerFileName << "'." << LL_ENDL;
+ }
+ }
+
+ // now check for cases in which the exec marker may have been cleaned up by crash handlers
+
+ // check for any last exec event report based on whether or not it happened during logout
+ // (the logout marker is created when logout begins)
+ std::string logout_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOGOUT_MARKER_FILE_NAME);
+ if(LLAPRFile::isExist(logout_marker_file, LL_APR_RB))
+ {
+ if (markerIsSameVersion(logout_marker_file))
+ {
+ gLastExecEvent = LAST_EXEC_LOGOUT_FROZE;
+ LL_INFOS("MarkerFile") << "Logout crash marker '"<< logout_marker_file << "', changing LastExecEvent to LOGOUT_FROZE" << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS("MarkerFile") << "Logout crash marker '"<< logout_marker_file << "' found, but versions did not match" << LL_ENDL;
+ }
+ LLAPRFile::remove(logout_marker_file);
+ }
+ // further refine based on whether or not a marker created during an llerr crash is found
+ std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME);
+ if(LLAPRFile::isExist(llerror_marker_file, LL_APR_RB))
+ {
+ if (markerIsSameVersion(llerror_marker_file))
+ {
+ if ( gLastExecEvent == LAST_EXEC_LOGOUT_FROZE )
+ {
+ gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
+ LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL;
+ }
+ else
+ {
+ gLastExecEvent = LAST_EXEC_LLERROR_CRASH;
+ LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LLERROR_CRASH" << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' found, but versions did not match" << LL_ENDL;
+ }
+ LLAPRFile::remove(llerror_marker_file);
+ }
+ // and last refine based on whether or not a marker created during a non-llerr crash is found
+ std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME);
+ if(LLAPRFile::isExist(error_marker_file, LL_APR_RB))
+ {
+ if (markerIsSameVersion(error_marker_file))
+ {
+ if (gLastExecEvent == LAST_EXEC_LOGOUT_FROZE)
+ {
+ gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
+ LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL;
+ }
+ else
+ {
+ gLastExecEvent = LAST_EXEC_OTHER_CRASH;
+ LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' marker found, but versions did not match" << LL_ENDL;
+ }
+ LLAPRFile::remove(error_marker_file);
+ }
+}
+
+void LLAppViewer::removeMarkerFiles()
+{
+ if (!mSecondInstance)
+ {
+ if (mMarkerFile.getFileHandle())
+ {
+ mMarkerFile.close() ;
+ LLAPRFile::remove( mMarkerFileName );
+ LL_DEBUGS("MarkerFile") << "removed exec marker '"<getExpandedFilename(LL_PATH_DUMP, "");
gDirUtilp->deleteDirAndContents(dump_dir);
+#endif
}
void LLAppViewer::forceQuit()
@@ -3050,7 +3284,7 @@ void LLAppViewer::fastQuit(S32 error_code)
// figure out the error code
S32 final_error_code = error_code ? error_code : (S32)isError();
// this isn't a crash
- removeMarkerFile();
+ removeMarkerFiles();
// get outta here
_exit(final_error_code);
}
@@ -3171,8 +3405,7 @@ void LLAppViewer::migrateCacheDirectory()
{
gSavedSettings.setBOOL("MigrateCacheDirectory", FALSE);
- std::string delimiter = gDirUtilp->getDirDelimiter();
- std::string old_cache_dir = gDirUtilp->getOSUserAppDir() + delimiter + "cache";
+ std::string old_cache_dir = gDirUtilp->add(gDirUtilp->getOSUserAppDir(), "cache");
std::string new_cache_dir = gDirUtilp->getCacheDir(true);
if (gDirUtilp->fileExists(old_cache_dir))
@@ -3188,8 +3421,8 @@ void LLAppViewer::migrateCacheDirectory()
while (iter.next(file_name))
{
if (file_name == "." || file_name == "..") continue;
- std::string source_path = old_cache_dir + delimiter + file_name;
- std::string dest_path = new_cache_dir + delimiter + file_name;
+ std::string source_path = gDirUtilp->add(old_cache_dir, file_name);
+ std::string dest_path = gDirUtilp->add(new_cache_dir, file_name);
if (!LLFile::rename(source_path, dest_path))
{
file_count++;
@@ -3239,6 +3472,7 @@ void dumpVFSCaches()
gStaticVFS->dumpFiles();
SetCurrentDirectory(w_str);
#endif
+
LL_INFOS() << "========= Dynamic VFS ====" << LL_ENDL;
gVFS->listFiles();
#if LL_WINDOWS
@@ -3299,6 +3533,7 @@ bool LLAppViewer::initCache()
if (gSavedSettings.getBOOL("PurgeCacheOnStartup") ||
gSavedSettings.getBOOL("PurgeCacheOnNextStartup"))
{
+ LL_INFOS("AppCache") << "Startup cache purge requested: " << (gSavedSettings.getBOOL("PurgeCacheOnStartup") ? "ALWAYS" : "ONCE") << LL_ENDL;
gSavedSettings.setBOOL("PurgeCacheOnNextStartup", false);
mPurgeCache = true;
// STORM-1141 force purgeAllTextures to get called to prevent a crash here. -brad
@@ -3314,6 +3549,7 @@ bool LLAppViewer::initCache()
std::string new_cache_location = gSavedSettings.getString("NewCacheLocation");
if (new_cache_location != cache_location)
{
+ LL_INFOS("AppCache") << "Cache location changed, cache needs purging" << LL_ENDL;
gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation"));
purgeCache(); // purge old cache
gSavedSettings.setString("CacheLocation", new_cache_location);
@@ -3341,6 +3577,7 @@ bool LLAppViewer::initCache()
std::random_device rnddev;
std::mt19937 rng(rnddev());
std::uniform_int_distribution<> dist(0, 4);
+
LLSplashScreen::update(LLTrans::getString(
llformat("StartupInitializingTextureCache%d", dist(rng))));
}
@@ -3385,7 +3622,7 @@ bool LLAppViewer::initCache()
// This has to happen BEFORE starting the vfs
// time_t ltime;
- srand(time(NULL)); // Flawfinder: ignore
+ srand(time(nullptr)); // Flawfinder: ignore
U32 old_salt = gSavedSettings.getU32("VFSSalt");
U32 new_salt;
std::string old_vfs_data_file;
@@ -3427,10 +3664,10 @@ bool LLAppViewer::initCache()
LLDirIterator iter(dir, mask);
if (iter.next(found_file))
{
- old_vfs_data_file = dir + gDirUtilp->getDirDelimiter() + found_file;
+ old_vfs_data_file = gDirUtilp->add(dir, found_file);
- S32 start_pos = found_file.find_last_of('.');
- if (start_pos > 0)
+ size_t start_pos = found_file.find_last_of('.');
+ if (start_pos != std::string::npos && start_pos != 0)
{
sscanf(found_file.substr(start_pos+1).c_str(), "%d", &old_salt);
}
@@ -3539,7 +3776,7 @@ void LLAppViewer::purgeCache()
const std::string& LLAppViewer::getSecondLifeTitle() const
{
- return gSecondLife;
+ return LLTrans::getString("APP_NAME");
}
const std::string& LLAppViewer::getWindowTitle() const
@@ -3576,9 +3813,9 @@ void LLAppViewer::forceDisconnect(const std::string& mesg)
return;
}
- // Translate the message if possible
+ // *TODO: Translate the message if possible
std::string big_reason = LLAgent::sTeleportErrorMessages[mesg];
- if ( big_reason.size() == 0 )
+ if (big_reason.empty())
{
big_reason = mesg;
}
@@ -3609,26 +3846,25 @@ void LLAppViewer::badNetworkHandler()
mPurgeOnExit = TRUE;
- std::string grid_support_msg = "";
- if (!gHippoGridManager->getCurrentGrid()->getSupportUrl().empty())
- {
- grid_support_msg = "\n\nOr visit the grid support page at: \n "
- + gHippoGridManager->getCurrentGrid()->getSupportUrl();
- }
std::ostringstream message;
message <<
"The viewer has detected mangled network data indicative\n"
"of a bad upstream network connection or an incomplete\n"
- "local installation of " << gSecondLife << ". \n"
+ "local installation of " << LLAppViewer::instance()->getSecondLifeTitle() << ". \n"
" \n"
"Try uninstalling and reinstalling to see if this resolves \n"
"the issue. \n"
" \n"
"If the problem continues, please report the issue at: \n"
- "http://www.singularityviewer.org" << grid_support_msg;
+ "http://www.singularityviewer.org";
+
+ if (!gHippoGridManager->getCurrentGrid()->getSupportUrl().empty())
+ {
+ message << "\n\nOr visit the grid support page at: \n"
+ << gHippoGridManager->getCurrentGrid()->getSupportUrl();
+ }
+
forceDisconnect(message.str());
-
- LLApp::instance()->writeMiniDump();
}
// This routine may get called more than once during the shutdown process.
@@ -3659,11 +3895,11 @@ void LLAppViewer::saveFinalSnapshot()
void LLAppViewer::loadNameCache()
{
- // Phoenix: Wolfspirit: Loads the Display Name Cache. And set if we are using Display Names.
+ // display names cache
std::string filename =
gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml");
LL_INFOS("AvNameCache") << filename << LL_ENDL;
- llifstream name_cache_stream(filename);
+ llifstream name_cache_stream(filename.c_str());
if(name_cache_stream.is_open())
{
LLAvatarNameCache::importFile(name_cache_stream);
@@ -3673,7 +3909,7 @@ void LLAppViewer::loadNameCache()
std::string name_cache;
name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache");
- llifstream cache_file(name_cache);
+ llifstream cache_file(name_cache.c_str());
if(cache_file.is_open())
{
if(gCacheName->importFile(cache_file)) return;
@@ -3682,26 +3918,29 @@ void LLAppViewer::loadNameCache()
void LLAppViewer::saveNameCache()
{
- // Phoenix: Wolfspirit: Saves the Display Name Cache.
+ // display names cache
std::string filename =
gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml");
- llofstream name_cache_stream(filename);
+ llofstream name_cache_stream(filename.c_str());
if(name_cache_stream.is_open())
{
LLAvatarNameCache::exportFile(name_cache_stream);
}
- if (!gCacheName) return;
-
- std::string name_cache;
- name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache");
- llofstream cache_file(name_cache);
- if(cache_file.is_open())
- {
- gCacheName->exportFile(cache_file);
+ // real names cache
+ if (gCacheName)
+ {
+ std::string name_cache;
+ name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache");
+ llofstream cache_file(name_cache.c_str());
+ if(cache_file.is_open())
+ {
+ gCacheName->exportFile(cache_file);
+ }
}
}
+
/*! @brief This class is an LLFrameTimer that can be created with
an elapsed time that starts counting up from the given value
rather than 0.0.
@@ -3781,11 +4020,12 @@ void LLAppViewer::idle()
// Smoothly weight toward current frame
gFPSClamped = (frame_rate_clamped + (4.f * gFPSClamped)) / 5.f;
- F32 qas = gSavedSettings.getF32("QuitAfterSeconds");
+ static LLCachedControl qas(gSavedSettings, "QuitAfterSeconds");
if (qas > 0.f)
{
if (gRenderStartTime.getElapsedTimeF32() > qas)
{
+ LL_INFOS() << "Quitting after " << qas << " seconds. See setting \"QuitAfterSeconds\"." << LL_ENDL;
LLAppViewer::instance()->forceQuit();
}
}
@@ -3842,7 +4082,8 @@ void LLAppViewer::idle()
// Update simulator agent state
//
- if (gSavedSettings.getBOOL("RotateRight"))
+ static LLCachedControl rotateRight(gSavedSettings, "RotateRight");
+ if (rotateRight)
{
gAgent.moveYaw(-1.f);
}
@@ -3859,7 +4100,8 @@ void LLAppViewer::idle()
// When appropriate, update agent location to the simulator.
F32 agent_update_time = agent_update_timer.getElapsedTimeF32();
- BOOL flags_changed = gAgent.controlFlagsDirty() || (last_control_flags != gAgent.getControlFlags());
+ BOOL flags_changed = gAgent.controlFlagsDirty()
+ || (last_control_flags != gAgent.getControlFlags());
if (flags_changed || (agent_update_time > (1.0f / (F32)AGENT_UPDATES_PER_SECOND)))
{
@@ -3885,7 +4127,7 @@ void LLAppViewer::idle()
reset_statistics();
// Update session stats every large chunk of time
- // *FIX: (???) SAMANTHA
+ // *FIX: (?) SAMANTHA
if (viewer_stats_timer.getElapsedTimeF32() >= SEND_STATS_PERIOD && !gDisconnected)
{
LL_INFOS() << "Transmitting sessions stats" << LL_ENDL;
@@ -4304,13 +4546,11 @@ void LLAppViewer::sendLogoutRequest()
//Set internal status variables and marker files
gLogoutInProgress = TRUE;
mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME);
-
- LLAPRFile outfile(mLogoutMarkerFileName, LL_APR_W);
- mLogoutMarkerFile = outfile.getFileHandle() ;
- if (mLogoutMarkerFile)
+
+ if (mLogoutMarkerFile.open(mLogoutMarkerFileName, LL_APR_W) == APR_SUCCESS)
{
LL_INFOS() << "Created logout marker file " << mLogoutMarkerFileName << LL_ENDL;
- apr_file_close(mLogoutMarkerFile);
+ mLogoutMarkerFile.close();
}
else
{
@@ -4632,26 +4872,31 @@ void LLAppViewer::disconnectViewer()
void LLAppViewer::forceErrorLLError()
{
- LL_ERRS() << "This is an llerror" << LL_ENDL;
+ LL_ERRS() << "This is a deliberate llerror" << LL_ENDL;
}
void LLAppViewer::forceErrorBreakpoint()
{
+ LL_WARNS() << "Forcing a deliberate breakpoint" << LL_ENDL;
#ifdef LL_WINDOWS
DebugBreak();
+#else
+ asm ("int $3");
#endif
return;
}
void LLAppViewer::forceErrorBadMemoryAccess()
{
- S32* crash = NULL;
+ LL_WARNS() << "Forcing a deliberate bad memory access" << LL_ENDL;
+ S32* crash = nullptr;
*crash = 0xDEADBEEF;
return;
}
void LLAppViewer::forceErrorInfiniteLoop()
{
+ LL_WARNS() << "Forcing a deliberate infinite loop" << LL_ENDL;
while(true)
{
;
@@ -4661,13 +4906,15 @@ void LLAppViewer::forceErrorInfiniteLoop()
void LLAppViewer::forceErrorSoftwareException()
{
+ LL_WARNS() << "Forcing a deliberate exception" << LL_ENDL;
// *FIX: Any way to insure it won't be handled?
throw;
}
void LLAppViewer::forceErrorDriverCrash()
{
- glDeleteTextures(1, NULL);
+ LL_WARNS() << "Forcing a deliberate driver crash" << LL_ENDL;
+ glDeleteTextures(1, nullptr);
}
void LLAppViewer::initMainloopTimeout(const std::string& state, F32 secs)
@@ -4684,7 +4931,7 @@ void LLAppViewer::destroyMainloopTimeout()
if(mMainloopTimeout)
{
delete mMainloopTimeout;
- mMainloopTimeout = NULL;
+ mMainloopTimeout = nullptr;
}
}
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index e646aa2b5..06da8ee82 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -76,6 +76,7 @@ public:
bool quitRequested() { return mQuitRequested; }
bool logoutRequestSent() { return mLogoutRequestSent; }
+ bool isSecondInstance() { return mSecondInstance; }
void writeDebugInfo(bool isStatic=true);
@@ -86,7 +87,7 @@ public:
virtual bool restoreErrorTrap() = 0; // Require platform specific override to reset error handling mechanism.
// return false if the error trap needed restoration.
- virtual void initCrashReporting(bool reportFreeze = false) = 0; // What to do with crash report?
+ void initCrashReporting(); // What to do with crash report?
static void handleViewerCrash(); // Hey! The viewer crashed. Do this, soon.
// Thread accessors
@@ -113,7 +114,7 @@ public:
void loadNameCache();
void saveNameCache();
- void removeMarkerFile(bool leave_logout_marker = false);
+ void removeMarkerFiles();
void removeDumpDir();
// LLAppViewer testing helpers.
@@ -125,14 +126,13 @@ public:
virtual void forceErrorSoftwareException();
virtual void forceErrorDriverCrash();
- // *NOTE: There are currently 3 settings files:
- // "Global", "PerAccount" and "CrashSettings"
+ // *NOTE: There are currently 2 settings files:
+ // "Global", and "PerAccount"
// The list is found in app_settings/settings_files.xml
// but since they are used explicitly in code,
// the follow consts should also do the trick.
static const std::string sGlobalSettingsName;
static const std::string sPerAccountSettingsName;
- static const std::string sCrashSettingsName;
// Load settings from the location specified by loction_key.
// Key availale and rules for loading, are specified in
@@ -158,6 +158,7 @@ public:
void handleLoginComplete();
LLAllocator & getAllocator() { return mAlloc; }
+
// On LoginCompleted callback
typedef boost::signals2::signal login_completed_signal_t;
login_completed_signal_t mOnLoginCompleted;
@@ -172,7 +173,8 @@ public:
static void metricsSend(bool enable_reporting);
protected:
virtual bool initWindow(); // Initialize the viewer's window.
- virtual bool initLogging(); // Initialize log files, logging system, return false on failure.
+ virtual void initLoggingAndGetLastDuration(); // Initialize log files, logging system
+ void initLoggingInternal();
virtual void initConsole() {}; // Initialize OS level debugging console.
virtual bool initHardwareTest() { return true; } // A false result indicates the app should quit.
virtual bool initSLURLHandler();
@@ -189,7 +191,6 @@ private:
void initMaxHeapSize();
bool initThreads(); // Initialize viewer threads, return false on failure.
bool initConfiguration(); // Initialize settings from the command line/config file.
-
bool initCache(); // Initialize local client cache.
void checkMemory() ;
@@ -202,8 +203,9 @@ private:
void writeSystemInfo(); // Write system info to "debug_info.log"
- bool anotherInstanceRunning();
- void initMarkerFile();
+ void processMarkerFiles();
+ static void recordMarkerVersion(LLAPRFile& marker_file);
+ bool markerIsSameVersion(const std::string& marker_name) const;
void idle();
void idleShutdown();
@@ -226,8 +228,7 @@ private:
LLAPRFile mMarkerFile; // A file created to indicate the app is running.
std::string mLogoutMarkerFileName;
- apr_file_t* mLogoutMarkerFile; // A file created to indicate the app is running.
-
+ LLAPRFile mLogoutMarkerFile; // A file created to indicate the app is running.
LLOSInfo mSysOSInfo;
bool mReportedCrash;
diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp
index 764d36e4d..0f2957bc9 100644
--- a/indra/newview/llappviewerlinux.cpp
+++ b/indra/newview/llappviewerlinux.cpp
@@ -119,7 +119,6 @@ int main( int argc, char **argv )
}
delete viewer_app_ptr;
viewer_app_ptr = NULL;
-
return 0;
}
@@ -143,20 +142,12 @@ bool LLAppViewerLinux::init()
bool success = LLAppViewer::init();
-#if LL_SEND_CRASH_REPORTS
- if (success)
- {
- LLAppViewer* pApp = LLAppViewer::instance();
- pApp->initCrashReporting();
- }
-#endif
-
return success;
}
bool LLAppViewerLinux::restoreErrorTrap()
{
- // *NOTE:Mani there is a case for implementing this or the mac.
+ // *NOTE:Mani there is a case for implementing this on the mac.
// Linux doesn't need it to my knowledge.
return true;
}
@@ -347,12 +338,6 @@ bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url)
}
#endif // LL_DBUS_ENABLED
-void LLAppViewerLinux::initCrashReporting(bool reportFreeze)
-{
- // Singu Note: this is where original code forks crash logger process.
- // Singularity doesn't need it
-}
-
bool LLAppViewerLinux::beingDebugged()
{
static enum {unknown, no, yes} debugged = unknown;
@@ -397,7 +382,7 @@ bool LLAppViewerLinux::beingDebugged()
#endif
}
-bool LLAppViewerLinux::initLogging()
+void LLAppViewerLinux::initLoggingAndGetLastDuration()
{
// Remove the last stack trace, if any
// This file is no longer created, since the move to Google Breakpad
@@ -406,7 +391,7 @@ bool LLAppViewerLinux::initLogging()
gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
LLFile::remove(old_stack_file);
- return LLAppViewer::initLogging();
+ LLAppViewer::initLoggingAndGetLastDuration();
}
bool LLAppViewerLinux::initParseCommandLine(LLCommandLineParser& clp)
diff --git a/indra/newview/llappviewerlinux.h b/indra/newview/llappviewerlinux.h
index 6de13b81c..a751ad10b 100644
--- a/indra/newview/llappviewerlinux.h
+++ b/indra/newview/llappviewerlinux.h
@@ -66,7 +66,7 @@ protected:
virtual bool restoreErrorTrap();
virtual void initCrashReporting(bool reportFreeze);
- virtual bool initLogging();
+ virtual void initLoggingAndGetLastDuration();
virtual bool initParseCommandLine(LLCommandLineParser& clp);
virtual bool initSLURLHandler();
diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp
index 300480634..d4eef2b2b 100644
--- a/indra/newview/llappviewermacosx.cpp
+++ b/indra/newview/llappviewermacosx.cpp
@@ -260,12 +260,6 @@ bool LLAppViewerMacOSX::restoreErrorTrap()
return reset_count == 0;
}
-void LLAppViewerMacOSX::initCrashReporting(bool reportFreeze)
-{
- // Singu Note: this is where original code forks crash logger process.
- // Singularity doesn't need it
-}
-
std::string LLAppViewerMacOSX::generateSerialNumber()
{
char serial_md5[MD5HEX_STR_SIZE]; // Flawfinder: ignore
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 9ca2feeb6..3dc530a57 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -32,12 +32,6 @@
#include "llviewerprecompiledheaders.h"
-#if defined(_DEBUG)
-# if _MSC_VER >= 1400 // Visual C++ 2005 or later
-# define WINDOWS_CRT_MEM_CHECKS 1
-# endif
-#endif
-
#include "llwindowwin32.h" // *FIX: for setting gIconResource.
#include "llappviewerwin32.h"
@@ -73,19 +67,6 @@
#include "llcommandlineparser.h"
#include "lltrans.h"
-// *FIX:Mani - This hack is to fix a linker issue with libndofdev.lib
-// The lib was compiled under VS2005 - in VS2003 we need to remap assert
-#ifdef LL_DEBUG
-#ifdef LL_MSVC7
-extern "C" {
- void _wassert(const wchar_t * _Message, const wchar_t *_File, unsigned _Line)
- {
- LL_ERRS() << _Message << LL_ENDL;
- }
-}
-#endif
-#endif
-
const std::string LLAppViewerWin32::sWindowClass = "Second Life";
// Create app mutex creates a unique global windows object.
@@ -101,7 +82,7 @@ bool create_app_mutex()
bool result = true;
LPCWSTR unique_mutex_name = L"SecondLifeAppMutex";
HANDLE hMutex;
- hMutex = CreateMutex(NULL, TRUE, unique_mutex_name);
+ hMutex = CreateMutex(nullptr, TRUE, unique_mutex_name);
if(GetLastError() == ERROR_ALREADY_EXISTS)
{
result = false;
@@ -240,7 +221,9 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
LLAppViewerWin32* viewer_app_ptr = new LLAppViewerWin32(lpCmdLine);
+#if !defined(USE_CRASHPAD)
viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
+#endif
// Set a debug info flag to indicate if multiple instances are running.
bool found_other_instance = !create_app_mutex();
@@ -332,7 +315,7 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
}
delete viewer_app_ptr;
- viewer_app_ptr = NULL;
+ viewer_app_ptr = nullptr;
//start updater
if(LLAppViewer::sUpdaterInfo)
@@ -392,13 +375,13 @@ void LLAppViewerWin32::disableWinErrorReporting()
const S32 MAX_CONSOLE_LINES = 500;
-void create_console()
+static bool create_console()
{
CONSOLE_SCREEN_BUFFER_INFO coninfo;
// allocate a console for this app
- AllocConsole();
+ const bool isConsoleAllocated = AllocConsole();
// set the screen buffer to be big enough to let us scroll text
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
@@ -410,16 +393,16 @@ void create_console()
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
- setvbuf( stdin, NULL, _IONBF, 0 );
- setvbuf( stdout, NULL, _IONBF, 0 );
- setvbuf( stderr, NULL, _IONBF, 0 );
-
+ setvbuf( stdin, nullptr, _IONBF, 0 );
+ setvbuf( stdout, nullptr, _IONBF, 0 );
+ setvbuf( stderr, nullptr, _IONBF, 0 );
+ return isConsoleAllocated;
}
-
LLAppViewerWin32::LLAppViewerWin32(const char* cmd_line) :
- mCmdLine(cmd_line)
+ mCmdLine(cmd_line),
+ mIsConsoleAllocated(false)
{
}
@@ -442,15 +425,6 @@ bool LLAppViewerWin32::init()
LLWinDebug::instance().init();
#endif
-#if LL_WINDOWS
-#if LL_SEND_CRASH_REPORTS
-
- LLAppViewer* pApp = LLAppViewer::instance();
- pApp->initCrashReporting();
-
-#endif
-#endif
-
bool success = LLAppViewer::init();
return success;
@@ -462,18 +436,24 @@ bool LLAppViewerWin32::cleanup()
gDXHardware.cleanup();
+ if (mIsConsoleAllocated)
+ {
+ FreeConsole();
+ mIsConsoleAllocated = false;
+ }
+
return result;
}
-bool LLAppViewerWin32::initLogging()
+void LLAppViewerWin32::initLoggingAndGetLastDuration()
{
- return LLAppViewer::initLogging();
+ LLAppViewer::initLoggingAndGetLastDuration();
}
void LLAppViewerWin32::initConsole()
{
// pop up debug console
- create_console();
+ mIsConsoleAllocated = create_console();
return LLAppViewer::initConsole();
}
@@ -571,7 +551,7 @@ bool LLAppViewerWin32::initParseCommandLine(LLCommandLineParser& clp)
}
// Find the system language.
- FL_Locale *locale = NULL;
+ FL_Locale *locale = nullptr;
FL_Success success = FL_FindLocale(&locale, FL_MESSAGES);
if (success != 0)
{
@@ -595,12 +575,6 @@ bool LLAppViewerWin32::initParseCommandLine(LLCommandLineParser& clp)
bool LLAppViewerWin32::restoreErrorTrap()
{
return true;
- //return LLWinDebug::checkExceptionHandler();
-}
-
-void LLAppViewerWin32::initCrashReporting(bool reportFreeze)
-{
- // Singu Note: we don't fork the crash logger on start
}
//virtual
@@ -610,9 +584,9 @@ bool LLAppViewerWin32::sendURLToOtherInstance(const std::string& url)
mbstowcs(window_class, sWindowClass.c_str(), 255);
window_class[255] = 0;
// Use the class instead of the window name.
- HWND other_window = FindWindow(window_class, NULL);
+ HWND other_window = FindWindow(window_class, nullptr);
- if (other_window != NULL)
+ if (other_window != nullptr)
{
LL_DEBUGS() << "Found other window with the name '" << getWindowTitle() << "'" << LL_ENDL;
COPYDATASTRUCT cds;
@@ -638,13 +612,13 @@ std::string LLAppViewerWin32::generateSerialNumber()
DWORD serial = 0;
DWORD flags = 0;
BOOL success = GetVolumeInformation(
- L"C:\\",
- NULL, // volume name buffer
+ TEXT("C:\\"),
+ nullptr, // volume name buffer
0, // volume name buffer size
&serial, // volume serial
- NULL, // max component length
+ nullptr, // max component length
&flags, // file system flags
- NULL, // file system name buffer
+ nullptr, // file system name buffer
0); // file system name buffer size
if (success)
{
diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h
index 757f6ea0c..96f834798 100644
--- a/indra/newview/llappviewerwin32.h
+++ b/indra/newview/llappviewerwin32.h
@@ -46,22 +46,20 @@ public:
//
// Main application logic
//
- virtual bool init(); // Override to do application initialization
- virtual bool cleanup();
+ bool init() override; // Override to do application initialization
+ bool cleanup() override;
protected:
- virtual bool initLogging(); // Override to clean stack_trace info.
- virtual void initConsole(); // Initialize OS level debugging console.
- virtual bool initHardwareTest(); // Win32 uses DX9 to test hardware.
- virtual bool initParseCommandLine(LLCommandLineParser& clp);
+ void initLoggingAndGetLastDuration() override; // Override to clean stack_trace info.
+ void initConsole() override; // Initialize OS level debugging console.
+ bool initHardwareTest() override; // Win32 uses DX9 to test hardware.
+ bool initParseCommandLine(LLCommandLineParser& clp) override;
- virtual bool restoreErrorTrap();
- virtual void initCrashReporting(bool reportFreeze);
+ bool restoreErrorTrap() override;
- virtual bool sendURLToOtherInstance(const std::string& url);
-
- std::string generateSerialNumber();
+ bool sendURLToOtherInstance(const std::string& url) override;
+ std::string generateSerialNumber() override;
static const std::string sWindowClass;
@@ -69,6 +67,7 @@ private:
void disableWinErrorReporting();
std::string mCmdLine;
+ bool mIsConsoleAllocated;
};
#endif // LL_LLAPPVIEWERWIN32_H
diff --git a/indra/newview/llcrashlogger.cpp b/indra/newview/llcrashlogger.cpp
deleted file mode 100644
index 6a6dfa861..000000000
--- a/indra/newview/llcrashlogger.cpp
+++ /dev/null
@@ -1,418 +0,0 @@
- /**
-* @file llcrashlogger.cpp
-* @brief Crash logger implementation
-*
-* $LicenseInfo:firstyear=2003&license=viewerlgpl$
-* Second Life Viewer Source Code
-* Copyright (C) 2010, Linden Research, Inc.
-*
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU Lesser General Public
-* License as published by the Free Software Foundation;
-* version 2.1 of the License only.
-*
-* This library is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public
-* License along with this library; if not, write to the Free Software
-* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-*
-* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
-* $/LicenseInfo$
-*/
-#include "llviewerprecompiledheaders.h"
-
-#include "llcrashlogger.h"
-#include "linden_common.h"
-#include "llstring.h"
-#include "indra_constants.h" // CRASH_BEHAVIOR_...
-#include "llerror.h"
-#include "llerrorcontrol.h"
-#include "lltimer.h"
-#include "lldir.h"
-#include "llfile.h"
-#include "llsdserialize.h"
-#include "lliopipe.h"
-#include "llpumpio.h"
-#include "llhttpclient.h"
-#include "llsdserialize.h"
-#include "llproxy.h"
-#include "llwindow.h"
-#include "lltrans.h"
-#include "aistatemachine.h"
-#include "boost/filesystem.hpp"
-
-class AIHTTPTimeoutPolicy;
-extern AIHTTPTimeoutPolicy crashLoggerResponder_timeout;
-extern const std::string OLD_LOG_FILE;
-
-class LLCrashLoggerResponder : public LLHTTPClient::ResponderWithResult
-{
-public:
- LLCrashLoggerResponder()
- {
- }
-
- virtual void httpFailure(void)
- {
- LL_WARNS() << "Crash report sending failed: " << mReason << LL_ENDL;
- }
-
- virtual void httpSuccess(void)
- {
- std::string msg = "Crash report successfully sent";
- if (mContent.has("message"))
- {
- msg += ": " + mContent["message"].asString();
- }
- LL_INFOS() << msg << LL_ENDL;
-
- if (mContent.has("report_id"))
- {
- gSavedSettings.setS32("CrashReportID", mContent["report_id"].asInteger());
- }
-
- }
-
- virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const
- {
- return crashLoggerResponder_timeout;
- }
-
- virtual char const* getName(void) const
- {
- return "LLCrashLoggerResponder";
- }
-};
-
-LLCrashLogger::LLCrashLogger() :
- mCrashBehavior(CRASH_BEHAVIOR_ALWAYS_SEND),
- mCrashInPreviousExec(false),
- mCrashHost("")
-{
-}
-
-LLCrashLogger::~LLCrashLogger()
-{
-
-}
-
-// TRIM_SIZE must remain larger than LINE_SEARCH_SIZE.
-const int TRIM_SIZE = 128000;
-const int LINE_SEARCH_DIST = 500;
-const std::string SKIP_TEXT = "\n ...Skipping... \n";
-void trimSLLog(std::string& sllog)
-{
- if(sllog.length() > TRIM_SIZE * 2)
- {
- std::string::iterator head = sllog.begin() + TRIM_SIZE;
- std::string::iterator tail = sllog.begin() + sllog.length() - TRIM_SIZE;
- std::string::iterator new_head = std::find(head, head - LINE_SEARCH_DIST, '\n');
- if(new_head != head - LINE_SEARCH_DIST)
- {
- head = new_head;
- }
-
- std::string::iterator new_tail = std::find(tail, tail + LINE_SEARCH_DIST, '\n');
- if(new_tail != tail + LINE_SEARCH_DIST)
- {
- tail = new_tail;
- }
-
- sllog.erase(head, tail);
- sllog.insert(head, SKIP_TEXT.begin(), SKIP_TEXT.end());
- }
-}
-
-std::string getStartupStateFromLog(std::string& sllog)
-{
- std::string startup_state = "STATE_FIRST";
- std::string startup_token = "Startup state changing from ";
-
- int index = sllog.rfind(startup_token);
- if (index < 0 || index + startup_token.length() > sllog.length()) {
- return startup_state;
- }
-
- // find new line
- char cur_char = sllog[index + startup_token.length()];
- std::string::size_type newline_loc = index + startup_token.length();
- while(cur_char != '\n' && newline_loc < sllog.length())
- {
- newline_loc++;
- cur_char = sllog[newline_loc];
- }
-
- // get substring and find location of " to "
- std::string state_line = sllog.substr(index, newline_loc - index);
- std::string::size_type state_index = state_line.find(" to ");
- startup_state = state_line.substr(state_index + 4, state_line.length() - state_index - 4);
-
- return startup_state;
-}
-
-bool miniDumpExists(const std::string& dumpDir)
-{
- bool found = false;
-
- try
- {
- if (!boost::filesystem::exists(dumpDir))
- {
- return false;
- }
-
- boost::filesystem::directory_iterator end_itr;
- for (boost::filesystem::directory_iterator i(dumpDir); i != end_itr; ++i)
- {
- if (!boost::filesystem::is_regular_file(i->status())) continue;
- if (".dmp" == i->path().extension())
- {
- found = true;
- break;
- }
- }
- }
- catch (const boost::filesystem::filesystem_error& e)
- {
- LL_WARNS() << "Failed to determine existance of the minidump file: '" + e.code().message() +"'" << LL_ENDL;
- }
-
- return found;
-}
-
-bool LLCrashLogger::readDebugFromXML(LLSD& dest, const std::string& filename )
-{
- std::string db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,filename);
- std::ifstream debug_log_file(db_file_name.c_str());
-
- // Look for it in the debug_info.log file
- if (debug_log_file.is_open())
- {
- LLSDSerialize::fromXML(dest, debug_log_file);
- debug_log_file.close();
- return true;
- }
- return false;
-}
-
-void LLCrashLogger::mergeLogs( LLSD src_sd )
-{
- LLSD::map_iterator iter = src_sd.beginMap();
- LLSD::map_iterator end = src_sd.endMap();
- for( ; iter != end; ++iter)
- {
- mDebugLog[iter->first] = iter->second;
- }
-}
-
-bool LLCrashLogger::readMinidump(std::string minidump_path)
-{
- size_t length=0;
-
- std::ifstream minidump_stream(minidump_path.c_str(), std::ios_base::in | std::ios_base::binary);
- if(minidump_stream.is_open())
- {
- minidump_stream.seekg(0, std::ios::end);
- length = (size_t)minidump_stream.tellg();
- minidump_stream.seekg(0, std::ios::beg);
-
- LLSD::Binary data;
- data.resize(length);
-
- minidump_stream.read(reinterpret_cast(&(data[0])),length);
- minidump_stream.close();
-
- mCrashInfo["Minidump"] = data;
- }
- return (length>0?true:false);
-}
-
-void LLCrashLogger::gatherFiles()
-{
- LL_INFOS() << "Gathering logs..." << LL_ENDL;
-
- LLSD static_sd;
- LLSD dynamic_sd;
-
- bool has_logs = readDebugFromXML( static_sd, "static_debug_info.log" );
- has_logs |= readDebugFromXML( dynamic_sd, "dynamic_debug_info.log" );
-
- if ( has_logs )
- {
- mDebugLog = static_sd;
- mergeLogs(dynamic_sd);
- mCrashInPreviousExec = mDebugLog["CrashNotHandled"].asBoolean();
-
- mFileMap["SecondLifeLog"] = mDebugLog["SLLog"].asString();
- mFileMap["SettingsXml"] = mDebugLog["SettingsFilename"].asString();
- if(mDebugLog.has("CAFilename"))
- {
- LLCurl::setCAFile(mDebugLog["CAFilename"].asString());
- }
- else
- {
- LLCurl::setCAFile(gDirUtilp->getCAFile());
- }
-
- LL_INFOS() << "Using log file from debug log " << mFileMap["SecondLifeLog"] << LL_ENDL;
- LL_INFOS() << "Using settings file from debug log " << mFileMap["SettingsXml"] << LL_ENDL;
- }
- else
- {
- // Figure out the filename of the second life log
- LLCurl::setCAFile(gDirUtilp->getCAFile());
- mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log");
- mFileMap["SettingsXml"] = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml");
- }
-
- if(mCrashInPreviousExec)
- {
- // Restarting after freeze.
- // Replace the log file ext with .old, since the
- // instance that launched this process has overwritten
- // SecondLife.log
- std::string log_filename = mFileMap["SecondLifeLog"];
- log_filename.replace(log_filename.size() - 4, 4, ".old");
- mFileMap["SecondLifeLog"] = log_filename;
- }
-
- gatherPlatformSpecificFiles();
-
- mCrashInfo["DebugLog"] = mDebugLog;
- mFileMap["StatsLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"stats.log");
- // Singu Note: we have just started again, log has been renamed
- mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, OLD_LOG_FILE);
-
- LL_INFOS() << "Encoding files..." << LL_ENDL;
-
- for(std::map::iterator itr = mFileMap.begin(); itr != mFileMap.end(); ++itr)
- {
- std::ifstream f((*itr).second.c_str());
- if(!f.is_open())
- {
- LL_INFOS() << "Can't find file " << (*itr).second << LL_ENDL;
- continue;
- }
- std::stringstream s;
- s << f.rdbuf();
-
- std::string crash_info = s.str();
- if(itr->first == "SecondLifeLog")
- {
- if(!mCrashInfo["DebugLog"].has("StartupState"))
- {
- mCrashInfo["DebugLog"]["StartupState"] = getStartupStateFromLog(crash_info);
- }
- trimSLLog(crash_info);
- }
-
- mCrashInfo[(*itr).first] = LLStringFn::strip_invalid_xml(rawstr_to_utf8(crash_info));
- }
-
- std::string minidump_path;
-
- // Add minidump as binary.
- bool has_minidump = mDebugLog.has("MinidumpPath");
-
- if (has_minidump)
- minidump_path = mDebugLog["MinidumpPath"].asString();
-
-
- if (has_minidump)
- {
- has_minidump = readMinidump(minidump_path);
- }
-
- if (!has_minidump) //Viewer was probably so hosed it couldn't write remaining data. Try brute force.
- {
- //Look for a filename at least 30 characters long in the dump dir which contains the characters MDMP as the first 4 characters in the file.
- typedef std::vector vec;
-
- std::string pathname = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"");
- vec file_vec = gDirUtilp->getFilesInDir(pathname);
- for(vec::const_iterator iter=file_vec.begin(); iter!=file_vec.end(); ++iter)
- {
- if ( ( iter->length() > 30 ) && (iter->rfind(".log") != (iter->length()-4) ) )
- {
- std::string fullname = pathname + *iter;
- std::ifstream fdat( fullname.c_str(), std::ifstream::binary);
- if (fdat)
- {
- char buf[5];
- fdat.read(buf,4);
- fdat.close();
- if (!strncmp(buf,"MDMP",4))
- {
- minidump_path = *iter;
- has_minidump = readMinidump(fullname);
- mDebugLog["MinidumpPath"] = fullname;
- }
- }
- }
- }
- }
-}
-
-LLSD LLCrashLogger::constructPostData()
-{
- return mCrashInfo;
-}
-
-
-bool LLCrashLogger::sendCrashLog(std::string dump_dir)
-{
- gDirUtilp->setDumpDir( dump_dir );
-
- std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
- "SingularityCrashReport");
- std::string report_file = dump_path + ".log";
-
- gatherFiles();
-
- LLSD post_data;
- post_data = constructPostData();
-
- LL_INFOS() << "Sending reports..." << LL_ENDL;
-
- std::ofstream out_file(report_file.c_str());
- LLSDSerialize::toPrettyXML(post_data, out_file);
- out_file.close();
-
- LLHTTPClient::post(mCrashHost, post_data, new LLCrashLoggerResponder());
-
- return true;
-}
-
-
-void LLCrashLogger::checkCrashDump()
-{
-#if LL_SEND_CRASH_REPORTS
- // 0 - ask, 1 - always send, 2 - never send
- S32 pref = gSavedSettings.getS32("CrashSubmitBehavior");
- if (pref == 2) return; //never send
-
- mCrashHost = gSavedSettings.getString("CrashHostUrl");
- std::string dumpDir = gDirUtilp->getDumpDir();
-
- // Do we have something to send, and somewhere to send it
- if (!mCrashHost.empty() && miniDumpExists(dumpDir))
- {
- if (pref == 1) // always send
- {
- sendCrashLog(dumpDir);
- }
- else // ask
- {
- U32 response = OSMessageBox(LLTrans::getString("MBFrozenCrashed"), LLTrans::getString("MBAlert"), OSMB_YESNO);
- if (response == OSBTN_YES)
- {
- sendCrashLog(dumpDir);
- }
- }
- }
-#endif
-}
diff --git a/indra/newview/llcrashlogger.h b/indra/newview/llcrashlogger.h
deleted file mode 100644
index c510acb98..000000000
--- a/indra/newview/llcrashlogger.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
-* @file llcrashlogger.h
-* @brief Crash Logger Definition
-*
-* $LicenseInfo:firstyear=2003&license=viewerlgpl$
-* Second Life Viewer Source Code
-* Copyright (C) 2010, Linden Research, Inc.
-*
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU Lesser General Public
-* License as published by the Free Software Foundation;
-* version 2.1 of the License only.
-*
-* This library is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public
-* License along with this library; if not, write to the Free Software
-* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-*
-* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
-* $/LicenseInfo$
-*/
-#ifndef LLCRASHLOGGER_H
-#define LLCRASHLOGGER_H
-
-#include
-
-#include "linden_common.h"
-
-#include "llapp.h"
-#include "llsd.h"
-#include "llcontrol.h"
-
-class LLCrashLogger
-{
-public:
- LLCrashLogger();
- virtual ~LLCrashLogger();
- S32 loadCrashBehaviorSetting();
- bool readDebugFromXML(LLSD& dest, const std::string& filename );
- void gatherFiles();
- void mergeLogs( LLSD src_sd );
-
- virtual void gatherPlatformSpecificFiles() {}
- bool saveCrashBehaviorSetting(S32 crash_behavior);
- bool sendCrashLog(std::string dump_dir);
- LLSD constructPostData();
- void setUserText(const std::string& text) { mCrashInfo["UserNotes"] = text; }
- S32 getCrashBehavior() { return mCrashBehavior; }
- bool readMinidump(std::string minidump_path);
- void checkCrashDump();
-
-protected:
- S32 mCrashBehavior;
- BOOL mCrashInPreviousExec;
- std::map mFileMap;
- std::string mGridName;
- std::string mProductName;
- LLSD mCrashInfo;
- std::string mCrashHost;
- LLSD mDebugLog;
-};
-
-#endif //LLCRASHLOGGER_H
diff --git a/indra/newview/llpanelgeneral.cpp b/indra/newview/llpanelgeneral.cpp
index d794e43da..30a0e6430 100644
--- a/indra/newview/llpanelgeneral.cpp
+++ b/indra/newview/llpanelgeneral.cpp
@@ -87,7 +87,7 @@ BOOL LLPanelGeneral::postBuild()
childSetValue("ui_auto_scale", gSavedSettings.getBOOL("UIAutoScale"));
LLComboBox* crash_behavior_combobox = getChild("crash_behavior_combobox");
- crash_behavior_combobox->setCurrentByIndex(gSavedSettings.getS32(CRASH_BEHAVIOR_SETTING));
+ crash_behavior_combobox->setValue(gSavedSettings.getS32("CrashSubmitBehavior"));
childSetValue("language_combobox", gSavedSettings.getString("Language"));
@@ -163,7 +163,7 @@ void LLPanelGeneral::apply()
gSavedSettings.setString("Language", childGetValue("language_combobox"));
LLComboBox* crash_behavior_combobox = getChild("crash_behavior_combobox");
- gSavedSettings.setS32(CRASH_BEHAVIOR_SETTING, crash_behavior_combobox->getCurrentIndex());
+ gSavedSettings.setS32("CrashSubmitBehavior", crash_behavior_combobox->getValue());
}
void LLPanelGeneral::cancel()
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index f7f8d22cb..1e4e210f2 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -94,7 +94,6 @@ AIThreadSafeDC gSettings;
LLControlGroup gSavedSettings("Global"); // saved at end of session
LLControlGroup gSavedPerAccountSettings("PerAccount"); // saved at end of session
LLControlGroup gColors("Colors"); // saved at end of session
-LLControlGroup gCrashSettings("CrashSettings"); // saved at end of session
std::string gLastRunVersion;
diff --git a/indra/newview/llviewercontrol.h b/indra/newview/llviewercontrol.h
index 0fd6b9cd4..203c5cfb3 100644
--- a/indra/newview/llviewercontrol.h
+++ b/indra/newview/llviewercontrol.h
@@ -62,9 +62,6 @@ void create_graphics_group(LLControlGroup& group);
// Read-only
extern LLControlGroup gColors;
-// Saved at end of session
-extern LLControlGroup gCrashSettings;
-
// Set after settings loaded
extern std::string gLastRunVersion;
diff --git a/indra/newview/skins/default/xui/en-us/notifications.xml b/indra/newview/skins/default/xui/en-us/notifications.xml
index 534d3eaa9..d9128f46c 100644
--- a/indra/newview/skins/default/xui/en-us/notifications.xml
+++ b/indra/newview/skins/default/xui/en-us/notifications.xml
@@ -11450,6 +11450,19 @@ Do you wish to export anyway?
Object successfully exported to: [FILENAME]
+
+Would you like to help improve [SHORT_APP_NAME] by sending crash reports?
+
+(You can change your answer in Preferences -> General -> Crash reports)
+
+
+
<Type region name>
- Ask before sending
- Always send
- Never send
+ Never send
+ Always send
diff --git a/indra/newview/skins/default/xui/en-us/strings.xml b/indra/newview/skins/default/xui/en-us/strings.xml
index 19985e967..6521e4b22 100644
--- a/indra/newview/skins/default/xui/en-us/strings.xml
+++ b/indra/newview/skins/default/xui/en-us/strings.xml
@@ -3833,6 +3833,7 @@ This can be because you somehow have multiple copies running, or your system inc
If this message persists, restart your computer and try again.
If it continues to persist, you may need to completely uninstall [APP_NAME] and reinstall it.
+ Fatal Error. Crash and Loop?
[APP_NAME] is already running.
Check your task bar for a minimized copy of the program.
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index cdfd3a8bf..b5e4a0a21 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -525,6 +525,12 @@ class WindowsManifest(ViewerManifest):
except:
print "Skipping msvc redist files"
+ # For crashpad
+ with self.prefix(src=pkgbindir):
+ self.path("crashpad_handler.exe")
+ if not self.is_packaging_viewer():
+ self.path("crashpad_handler.pdb")
+
self.path(src="licenses-win32.txt", dst="licenses.txt")
self.path("featuretable.txt")