Crash reporter moved to separate library

UAL moved back to networking
This commit is contained in:
Dale Glass 2023-06-26 00:21:14 +02:00
parent 6ec276c818
commit 4dcc2882fd
16 changed files with 339 additions and 308 deletions

View file

@ -230,7 +230,7 @@ link_hifi_libraries(
${PLATFORM_GL_BACKEND} ${PLATFORM_GL_BACKEND}
# Plaform specific input & display plugin libraries # Plaform specific input & display plugin libraries
${PLATFORM_PLUGIN_LIBRARIES} ${PLATFORM_PLUGIN_LIBRARIES}
shaders shaders monitoring
) )
include_hifi_library_headers(script-engine) include_hifi_library_headers(script-engine)

View file

@ -179,7 +179,7 @@
#include "avatar/AvatarPackager.h" #include "avatar/AvatarPackager.h"
#include "avatar/MyCharacterController.h" #include "avatar/MyCharacterController.h"
#include "CrashRecoveryHandler.h" #include "CrashRecoveryHandler.h"
#include "CrashHandler.h" #include "crash-handler/CrashHandler.h"
#include "DiscoverabilityManager.h" #include "DiscoverabilityManager.h"
#include "GLCanvas.h" #include "GLCanvas.h"
#include "InterfaceDynamicFactory.h" #include "InterfaceDynamicFactory.h"
@ -407,8 +407,10 @@ public:
} }
void deadlockDetectionCrash() { void deadlockDetectionCrash() {
setCrashAnnotation("_mod_faulting_tid", std::to_string((uint64_t)_mainThreadID)); auto &ch = CrashHandler::getInstance();
setCrashAnnotation("deadlock", "1");
ch.setAnnotation("_mod_faulting_tid", std::to_string((uint64_t)_mainThreadID));
ch.setAnnotation("deadlock", "1");
uint32_t* crashTrigger = nullptr; uint32_t* crashTrigger = nullptr;
*crashTrigger = 0xDEAD10CC; *crashTrigger = 0xDEAD10CC;
} }
@ -1054,9 +1056,11 @@ Application::Application(
{ {
// identify gpu as early as possible to help identify OpenGL initialization errors. // identify gpu as early as possible to help identify OpenGL initialization errors.
auto gpuIdent = GPUIdent::getInstance(); auto gpuIdent = GPUIdent::getInstance();
setCrashAnnotation("sentry[contexts][gpu][name]", gpuIdent->getName().toStdString()); auto &ch = CrashHandler::getInstance();
setCrashAnnotation("sentry[contexts][gpu][version]", gpuIdent->getDriver().toStdString());
setCrashAnnotation("gpu_memory", std::to_string(gpuIdent->getMemory())); ch.setAnnotation("sentry[contexts][gpu][name]", gpuIdent->getName().toStdString());
ch.setAnnotation("sentry[contexts][gpu][version]", gpuIdent->getDriver().toStdString());
ch.setAnnotation("gpu_memory", std::to_string(gpuIdent->getMemory()));
} }
// make sure the debug draw singleton is initialized on the main thread. // make sure the debug draw singleton is initialized on the main thread.
@ -1166,13 +1170,15 @@ Application::Application(
_logger->setSessionID(accountManager->getSessionID()); _logger->setSessionID(accountManager->getSessionID());
#endif #endif
setCrashAnnotation("metaverse_session_id", accountManager->getSessionID().toString().toStdString()); auto &ch = CrashHandler::getInstance();
setCrashAnnotation("main_thread_id", std::to_string((size_t)QThread::currentThreadId()));
ch.setAnnotation("metaverse_session_id", accountManager->getSessionID().toString().toStdString());
ch.setAnnotation("main_thread_id", std::to_string((size_t)QThread::currentThreadId()));
if (steamClient) { if (steamClient) {
qCDebug(interfaceapp) << "[VERSION] SteamVR buildID:" << steamClient->getSteamVRBuildID(); qCDebug(interfaceapp) << "[VERSION] SteamVR buildID:" << steamClient->getSteamVRBuildID();
} }
setCrashAnnotation("steam", property(hifi::properties::STEAM).toBool() ? "1" : "0"); ch.setAnnotation("steam", property(hifi::properties::STEAM).toBool() ? "1" : "0");
qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion()); qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion());
qCDebug(interfaceapp) << "[VERSION] MODIFIED_ORGANIZATION:" << BuildInfo::MODIFIED_ORGANIZATION; qCDebug(interfaceapp) << "[VERSION] MODIFIED_ORGANIZATION:" << BuildInfo::MODIFIED_ORGANIZATION;
@ -1236,7 +1242,8 @@ Application::Application(
connect(&domainHandler, SIGNAL(domainURLChanged(QUrl)), SLOT(domainURLChanged(QUrl))); connect(&domainHandler, SIGNAL(domainURLChanged(QUrl)), SLOT(domainURLChanged(QUrl)));
connect(&domainHandler, SIGNAL(redirectToErrorDomainURL(QUrl)), SLOT(goToErrorDomainURL(QUrl))); connect(&domainHandler, SIGNAL(redirectToErrorDomainURL(QUrl)), SLOT(goToErrorDomainURL(QUrl)));
connect(&domainHandler, &DomainHandler::domainURLChanged, [](QUrl domainURL){ connect(&domainHandler, &DomainHandler::domainURLChanged, [](QUrl domainURL){
setCrashAnnotation("domain", domainURL.toString().toStdString()); auto &ch = CrashHandler::getInstance();
ch.setAnnotation("domain", domainURL.toString().toStdString());
}); });
connect(&domainHandler, SIGNAL(resetting()), SLOT(resettingDomain())); connect(&domainHandler, SIGNAL(resetting()), SLOT(resettingDomain()));
connect(&domainHandler, SIGNAL(connectedToDomain(QUrl)), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(connectedToDomain(QUrl)), SLOT(updateWindowTitle()));
@ -1348,8 +1355,9 @@ Application::Application(
setPreferredCursor(Cursor::Manager::getIconName(Cursor::Icon::SYSTEM)); setPreferredCursor(Cursor::Manager::getIconName(Cursor::Icon::SYSTEM));
} }
setCrashAnnotation("display_plugin", displayPlugin->getName().toStdString()); auto &ch = CrashHandler::getInstance();
setCrashAnnotation("hmd", displayPlugin->isHmd() ? "1" : "0"); ch.setAnnotation("display_plugin", displayPlugin->getName().toStdString());
ch.setAnnotation("hmd", displayPlugin->isHmd() ? "1" : "0");
}); });
} }
connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateSystemTabletMode); connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateSystemTabletMode);
@ -1388,7 +1396,8 @@ Application::Application(
connect(myAvatar.get(), &MyAvatar::skeletonModelURLChanged, [](){ connect(myAvatar.get(), &MyAvatar::skeletonModelURLChanged, [](){
QUrl avatarURL = qApp->getMyAvatar()->getSkeletonModelURL(); QUrl avatarURL = qApp->getMyAvatar()->getSkeletonModelURL();
setCrashAnnotation("avatar", avatarURL.toString().toStdString()); auto &ch = CrashHandler::getInstance();
ch.setAnnotation("avatar", avatarURL.toString().toStdString());
}); });
// Inititalize sample before registering // Inititalize sample before registering
@ -2698,7 +2707,8 @@ void Application::updateHeartbeat() const {
} }
void Application::onAboutToQuit() { void Application::onAboutToQuit() {
setCrashAnnotation("shutdown", "1"); auto &ch = CrashHandler::getInstance();
ch.setAnnotation("shutdown", "1");
// quickly save AvatarEntityData before the EntityTree is dismantled // quickly save AvatarEntityData before the EntityTree is dismantled
getMyAvatar()->saveAvatarEntityDataToSettings(); getMyAvatar()->saveAvatarEntityDataToSettings();
@ -7147,7 +7157,8 @@ void Application::updateWindowTitle() const {
QString metaverseUsername = accountManager->getAccountInfo().getUsername(); QString metaverseUsername = accountManager->getAccountInfo().getUsername();
QString domainUsername = domainAccountManager->getUsername(); QString domainUsername = domainAccountManager->getUsername();
setCrashAnnotation("sentry[user][username]", metaverseUsername.toStdString()); auto &ch = CrashHandler::getInstance();
ch.setAnnotation("sentry[user][username]", metaverseUsername.toStdString());
QString currentPlaceName; QString currentPlaceName;
if (isServerlessMode()) { if (isServerlessMode()) {

View file

@ -34,6 +34,7 @@
#include <SettingManager.h> #include <SettingManager.h>
#include <DependencyManager.h> #include <DependencyManager.h>
#include <UserActivityLogger.h> #include <UserActivityLogger.h>
#include <crash-handler/CrashHandler.h>
#include <BuildInfo.h> #include <BuildInfo.h>
bool CrashRecoveryHandler::checkForResetSettings(bool wasLikelyCrash, bool suppressPrompt) { bool CrashRecoveryHandler::checkForResetSettings(bool wasLikelyCrash, bool suppressPrompt) {
@ -91,7 +92,7 @@ bool CrashRecoveryHandler::suggestCrashReporting() {
QVBoxLayout* layout = new QVBoxLayout; QVBoxLayout* layout = new QVBoxLayout;
QString explainText; QString explainText;
auto &ual = UserActivityLogger::getInstance(); auto &ch = CrashHandler::getInstance();
@ -119,7 +120,7 @@ bool CrashRecoveryHandler::suggestCrashReporting() {
break; break;
} }
if (!ual.isCrashMonitorStarted()) { if (!ch.isStarted()) {
qWarning() << "Crash reporting not working, skipping suggestion to enable it."; qWarning() << "Crash reporting not working, skipping suggestion to enable it.";
return false; return false;
} }
@ -131,8 +132,8 @@ bool CrashRecoveryHandler::suggestCrashReporting() {
QCheckBox* crashReportCheckbox = new QCheckBox("Enable automatic crash reporting"); QCheckBox* crashReportCheckbox = new QCheckBox("Enable automatic crash reporting");
crashReportCheckbox->setChecked(ual.isCrashReportingEnabled()); crashReportCheckbox->setChecked(ch.isEnabled());
crashReportCheckbox->setEnabled(ual.isCrashMonitorStarted()); crashReportCheckbox->setEnabled(ch.isStarted());
layout->addWidget(explainLabel); layout->addWidget(explainLabel);
layout->addSpacing(12); layout->addSpacing(12);
@ -149,7 +150,7 @@ bool CrashRecoveryHandler::suggestCrashReporting() {
crashDialog.exec(); crashDialog.exec();
ual.setCrashReportingEnabled(crashReportCheckbox->isChecked()); ch.setEnabled(crashReportCheckbox->isChecked());
return true; return true;
} }
@ -157,7 +158,7 @@ bool CrashRecoveryHandler::suggestCrashReporting() {
CrashRecoveryHandler::Action CrashRecoveryHandler::promptUserForAction(bool showCrashMessage) { CrashRecoveryHandler::Action CrashRecoveryHandler::promptUserForAction(bool showCrashMessage) {
QDialog crashDialog; QDialog crashDialog;
QLabel* label; QLabel* label;
auto &ual = UserActivityLogger::getInstance(); auto &ch = CrashHandler::getInstance();
if (showCrashMessage) { if (showCrashMessage) {
crashDialog.setWindowTitle("Interface Crashed Last Run"); crashDialog.setWindowTitle("Interface Crashed Last Run");
@ -176,7 +177,7 @@ CrashRecoveryHandler::Action CrashRecoveryHandler::promptUserForAction(bool show
QRadioButton* option3 = new QRadioButton("Continue with my current settings"); QRadioButton* option3 = new QRadioButton("Continue with my current settings");
QLabel* crashReportLabel = nullptr; QLabel* crashReportLabel = nullptr;
if (ual.isCrashMonitorStarted()) { if (ch.isStarted()) {
crashReportLabel = new QLabel("To help us with debugging, you can enable automatic crash reports.\n" crashReportLabel = new QLabel("To help us with debugging, you can enable automatic crash reports.\n"
"They'll only be seen by developers trusted by the Overte e.V. organization,\n" "They'll only be seen by developers trusted by the Overte e.V. organization,\n"
"and will only be used for improving the code."); "and will only be used for improving the code.");
@ -187,8 +188,8 @@ CrashRecoveryHandler::Action CrashRecoveryHandler::promptUserForAction(bool show
QCheckBox* crashReportCheckbox = new QCheckBox("Enable automatic crash reporting"); QCheckBox* crashReportCheckbox = new QCheckBox("Enable automatic crash reporting");
crashReportCheckbox->setChecked(ual.isCrashReportingEnabled()); crashReportCheckbox->setChecked(ch.isEnabled());
crashReportCheckbox->setEnabled(ual.isCrashMonitorStarted()); crashReportCheckbox->setEnabled(ch.isStarted());
option3->setChecked(true); option3->setChecked(true);
layout->addWidget(option1); layout->addWidget(option1);
@ -218,7 +219,7 @@ CrashRecoveryHandler::Action CrashRecoveryHandler::promptUserForAction(bool show
} }
} }
ual.setCrashReportingEnabled(crashReportCheckbox->isChecked()); ch.setEnabled(crashReportCheckbox->isChecked());
// Dialog cancelled or "do nothing" option chosen // Dialog cancelled or "do nothing" option chosen
return CrashRecoveryHandler::DO_NOTHING; return CrashRecoveryHandler::DO_NOTHING;

View file

@ -22,8 +22,8 @@
#include <plugins/SteamClientPlugin.h> #include <plugins/SteamClientPlugin.h>
#include <UserActivityLogger.h> #include <UserActivityLogger.h>
#include <UUID.h> #include <UUID.h>
#include <crash-handler/CrashHandler.h>
#include "CrashHandler.h"
#include "Menu.h" #include "Menu.h"
const Discoverability::Mode DEFAULT_DISCOVERABILITY_MODE = Discoverability::Connections; const Discoverability::Mode DEFAULT_DISCOVERABILITY_MODE = Discoverability::Connections;
@ -133,7 +133,8 @@ void DiscoverabilityManager::updateLocation() {
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
steamClient->updateLocation(domainHandler.getHostname(), currentAddress); steamClient->updateLocation(domainHandler.getHostname(), currentAddress);
} }
setCrashAnnotation("address", currentAddress.toString().toStdString());
CrashHandler::getInstance().setAnnotation("address", currentAddress.toString().toStdString());
} }
void DiscoverabilityManager::handleHeartbeatResponse(QNetworkReply* requestReply) { void DiscoverabilityManager::handleHeartbeatResponse(QNetworkReply* requestReply) {

View file

@ -57,6 +57,7 @@
#include "LocationBookmarks.h" #include "LocationBookmarks.h"
#include "DeferredLightingEffect.h" #include "DeferredLightingEffect.h"
#include "PickManager.h" #include "PickManager.h"
#include "crash-handler/CrashHandler.h"
#include "scripting/SettingsScriptingInterface.h" #include "scripting/SettingsScriptingInterface.h"
#if defined(Q_OS_MAC) || defined(Q_OS_WIN) #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
@ -636,12 +637,13 @@ Menu::Menu() {
true, true,
&UserActivityLogger::getInstance(), &UserActivityLogger::getInstance(),
SLOT(disable(bool))); SLOT(disable(bool)));
addCheckableActionToQMenuAndActionHash(networkMenu, addCheckableActionToQMenuAndActionHash(networkMenu,
MenuOption::EnableCrashReporting, MenuOption::EnableCrashReporting,
0, 0,
UserActivityLogger::getInstance().isCrashReportingEnabled(), CrashHandler::getInstance().isEnabled(),
&UserActivityLogger::getInstance(), &CrashHandler::getInstance(),
SLOT(setCrashReportingEnabled(bool))); SLOT(setEnabled(bool)));
addActionToQMenuAndActionHash(networkMenu, MenuOption::ShowDSConnectTable, 0, addActionToQMenuAndActionHash(networkMenu, MenuOption::ShowDSConnectTable, 0,
qApp, SLOT(loadDomainConnectionDialog())); qApp, SLOT(loadDomainConnectionDialog()));

View file

@ -12,8 +12,8 @@
#include "Application.h" #include "Application.h"
#include <shared/GlobalAppProperties.h> #include <shared/GlobalAppProperties.h>
#include <shared/QtHelpers.h> #include <shared/QtHelpers.h>
#include <crash-handler/CrashHandler.h>
#include "CrashHandler.h"
RenderEventHandler::RenderEventHandler(CheckCall checkCall, RenderCall renderCall) : RenderEventHandler::RenderEventHandler(CheckCall checkCall, RenderCall renderCall) :
_checkCall(checkCall), _checkCall(checkCall),
@ -29,7 +29,7 @@ RenderEventHandler::RenderEventHandler(CheckCall checkCall, RenderCall renderCal
void RenderEventHandler::initialize() { void RenderEventHandler::initialize() {
setObjectName("Render"); setObjectName("Render");
PROFILE_SET_THREAD_NAME("Render"); PROFILE_SET_THREAD_NAME("Render");
setCrashAnnotation("render_thread_id", std::to_string((size_t)QThread::currentThreadId())); CrashHandler::getInstance().setAnnotation("render_thread_id", std::to_string((size_t)QThread::currentThreadId()));
} }
void RenderEventHandler::resumeThread() { void RenderEventHandler::resumeThread() {

View file

@ -27,7 +27,7 @@
#include "AddressManager.h" #include "AddressManager.h"
#include "Application.h" #include "Application.h"
#include "CrashHandler.h" #include "crash-handler/CrashHandler.h"
#include "InterfaceLogging.h" #include "InterfaceLogging.h"
#include "UserActivityLogger.h" #include "UserActivityLogger.h"
#include "MainWindow.h" #include "MainWindow.h"
@ -37,7 +37,7 @@
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#include <Windows.h> #include <Windows.h>
extern "C" { extern "C" {
typedef int(__stdcall * CHECKMINSPECPROC) (); typedef int(__stdcall* CHECKMINSPECPROC)();
} }
#endif #endif
@ -51,7 +51,7 @@ int main(int argc, const char* argv[]) {
// This appears to resolve the issues with corrupted fonts on OSX. No // This appears to resolve the issues with corrupted fonts on OSX. No
// idea why. // idea why.
qputenv("QT_ENABLE_GLYPH_CACHE_WORKAROUND", "true"); qputenv("QT_ENABLE_GLYPH_CACHE_WORKAROUND", "true");
// https://i.kym-cdn.com/entries/icons/original/000/008/342/ihave.jpg // https://i.kym-cdn.com/entries/icons/original/000/008/342/ihave.jpg
QSurfaceFormat::setDefaultFormat(format); QSurfaceFormat::setDefaultFormat(format);
#endif #endif
@ -73,179 +73,88 @@ int main(int argc, const char* argv[]) {
QCommandLineOption helpOption = parser.addHelpOption(); QCommandLineOption helpOption = parser.addHelpOption();
QCommandLineOption versionOption = parser.addVersionOption(); QCommandLineOption versionOption = parser.addVersionOption();
QCommandLineOption urlOption( QCommandLineOption urlOption("url", "Start at specified URL location.", "string");
"url", QCommandLineOption protocolVersionOption("protocolVersion", "Writes the protocol version base64 signature to a file?",
"Start at specified URL location.", "path");
"string" QCommandLineOption noUpdaterOption("no-updater", "Do not show auto-updater.");
); QCommandLineOption
QCommandLineOption protocolVersionOption( checkMinSpecOption("checkMinSpec",
"protocolVersion", "Check if machine meets minimum specifications. The program will run if check passes.");
"Writes the protocol version base64 signature to a file?", QCommandLineOption runServerOption("runServer", "Run the server.");
"path" QCommandLineOption listenPortOption("listenPort", "Port to listen on.", "port_number");
); QCommandLineOption serverContentPathOption("serverContentPath",
QCommandLineOption noUpdaterOption( "Path to find server content.", // What content??
"no-updater", "path");
"Do not show auto-updater." QCommandLineOption overrideAppLocalDataPathOption("cache", "Set test cache.", "dir");
); QCommandLineOption scriptsOption("scripts",
QCommandLineOption checkMinSpecOption( "Set path for defaultScripts. These are probably scripts that run automatically. This "
"checkMinSpec", "parameter does not seem to work.",
"Check if machine meets minimum specifications. The program will run if check passes." "dir");
); QCommandLineOption allowMultipleInstancesOption("allowMultipleInstances", "Allow multiple instances to run.");
QCommandLineOption runServerOption( QCommandLineOption displaysOption("display", "Preferred display.", "displays");
"runServer", QCommandLineOption disableDisplaysOption("disable-displays",
"Run the server." "Displays to disable. Valid options include \"OpenVR (Vive)\" and \"Oculus Rift\"",
); "string");
QCommandLineOption listenPortOption( QCommandLineOption disableInputsOption("disable-inputs",
"listenPort", "Inputs to disable. Valid options include \"OpenVR (Vive)\" and \"Oculus Rift\"",
"Port to listen on.", "string");
"port_number" QCommandLineOption suppressSettingsResetOption("suppress-settings-reset",
); "Suppress the prompt to reset interface settings.");
QCommandLineOption serverContentPathOption( QCommandLineOption oculusStoreOption("oculus-store",
"serverContentPath", "Let the Oculus plugin know if interface was run from the Oculus Store.");
"Path to find server content.", // What content?? QCommandLineOption standaloneOption("standalone", "Emulate a standalone device.");
"path" QCommandLineOption disableWatchdogOption("disableWatchdog",
); "Disable the watchdog thread. The interface will crash on deadlocks.");
QCommandLineOption overrideAppLocalDataPathOption( QCommandLineOption systemCursorOption("system-cursor", "Use the default system cursor.");
"cache", QCommandLineOption
"Set test cache.", concurrentDownloadsOption("concurrent-downloads",
"dir" "Maximum concurrent resource downloads. Default is 16, except for Android where it is 4.",
); "integer");
QCommandLineOption scriptsOption( QCommandLineOption avatarURLOption("avatarURL", "Override the avatar U.R.L.", "url");
"scripts", QCommandLineOption replaceAvatarURLOption("replaceAvatarURL",
"Set path for defaultScripts. These are probably scripts that run automatically. This parameter does not seem to work.", "Replaces the avatar U.R.L. When used with --avatarURL, this takes precedence.",
"dir" "url");
); QCommandLineOption
QCommandLineOption allowMultipleInstancesOption( setBookmarkOption("setBookmark",
"allowMultipleInstances", "Set bookmark as key=value pair. Including the '=' symbol in either string is unsupported.",
"Allow multiple instances to run." "string");
); QCommandLineOption forceCrashReportingOption("forceCrashReporting", "Force crash reporting to initialize.");
QCommandLineOption displaysOption(
"display",
"Preferred display.",
"displays"
);
QCommandLineOption disableDisplaysOption(
"disable-displays",
"Displays to disable. Valid options include \"OpenVR (Vive)\" and \"Oculus Rift\"",
"string"
);
QCommandLineOption disableInputsOption(
"disable-inputs",
"Inputs to disable. Valid options include \"OpenVR (Vive)\" and \"Oculus Rift\"",
"string"
);
QCommandLineOption suppressSettingsResetOption(
"suppress-settings-reset",
"Suppress the prompt to reset interface settings."
);
QCommandLineOption oculusStoreOption(
"oculus-store",
"Let the Oculus plugin know if interface was run from the Oculus Store."
);
QCommandLineOption standaloneOption(
"standalone",
"Emulate a standalone device."
);
QCommandLineOption disableWatchdogOption(
"disableWatchdog",
"Disable the watchdog thread. The interface will crash on deadlocks."
);
QCommandLineOption systemCursorOption(
"system-cursor",
"Use the default system cursor."
);
QCommandLineOption concurrentDownloadsOption(
"concurrent-downloads",
"Maximum concurrent resource downloads. Default is 16, except for Android where it is 4.",
"integer"
);
QCommandLineOption avatarURLOption(
"avatarURL",
"Override the avatar U.R.L.",
"url"
);
QCommandLineOption replaceAvatarURLOption(
"replaceAvatarURL",
"Replaces the avatar U.R.L. When used with --avatarURL, this takes precedence.",
"url"
);
QCommandLineOption setBookmarkOption(
"setBookmark",
"Set bookmark as key=value pair. Including the '=' symbol in either string is unsupported.",
"string"
);
QCommandLineOption forceCrashReportingOption(
"forceCrashReporting",
"Force crash reporting to initialize."
);
// The documented "--disable-lod" does not seem to exist. // The documented "--disable-lod" does not seem to exist.
// Below are undocumented. // Below are undocumented.
QCommandLineOption noLauncherOption( QCommandLineOption noLauncherOption("no-launcher",
"no-launcher", "Supposedly does something for the server, unrelated to the application launcher. The "
"Supposedly does something for the server, unrelated to the application launcher. The feature may never have been implemented." "feature may never have been implemented.");
); QCommandLineOption
QCommandLineOption overrideScriptsPathOption( overrideScriptsPathOption("overrideScriptsPath",
"overrideScriptsPath", "Specifies path to default directory where the application will look for scripts to load.",
"Specifies path to default directory where the application will look for scripts to load.", "string");
"string" QCommandLineOption defaultScriptsOverrideOption("defaultScriptsOverride",
); "Override default script to run automatically on start. Default is "
QCommandLineOption defaultScriptsOverrideOption( "\"defaultsScripts.js\".",
"defaultScriptsOverride", "string");
"Override default script to run automatically on start. Default is \"defaultsScripts.js\".", QCommandLineOption responseTokensOption("tokens", "Set response tokens <json>.", "json");
"string" QCommandLineOption displayNameOption("displayName", "Set user display name <string>.", "string");
); QCommandLineOption noLoginOption("no-login-suggestion", "Do not show log-in dialogue.");
QCommandLineOption responseTokensOption( QCommandLineOption
"tokens", traceFileOption("traceFile",
"Set response tokens <json>.", "Writes a trace to a file in the documents folder. Only works if \"--traceDuration\" is specified.",
"json" "path");
); QCommandLineOption
QCommandLineOption displayNameOption( traceDurationOption("traceDuration",
"displayName", "Automatically quit interface after duration. Only works if \"--traceFile\" is specified.",
"Set user display name <string>.", "seconds");
"string" QCommandLineOption clockSkewOption("clockSkew", "Forces client instance's clock to skew for demonstration purposes.",
); "integer"); // This should probably be removed.
QCommandLineOption noLoginOption( QCommandLineOption testScriptOption("testScript", "Undocumented. Accepts parameter as U.R.L.", "string");
"no-login-suggestion", QCommandLineOption testResultsLocationOption("testResultsLocation", "Undocumented", "path");
"Do not show log-in dialogue."
);
QCommandLineOption traceFileOption(
"traceFile",
"Writes a trace to a file in the documents folder. Only works if \"--traceDuration\" is specified.",
"path"
);
QCommandLineOption traceDurationOption(
"traceDuration",
"Automatically quit interface after duration. Only works if \"--traceFile\" is specified.",
"seconds"
);
QCommandLineOption clockSkewOption(
"clockSkew",
"Forces client instance's clock to skew for demonstration purposes.",
"integer"
); // This should probably be removed.
QCommandLineOption testScriptOption(
"testScript",
"Undocumented. Accepts parameter as U.R.L.",
"string"
);
QCommandLineOption testResultsLocationOption(
"testResultsLocation",
"Undocumented",
"path"
);
QCommandLineOption quitWhenFinishedOption( QCommandLineOption quitWhenFinishedOption(
"quitWhenFinished", "quitWhenFinished",
"Only works if \"--testScript\" is provided." "Only works if \"--testScript\" is provided."); // Should probably also be made to work on testResultsLocationOption.
); // Should probably also be made to work on testResultsLocationOption. QCommandLineOption fastHeartbeatOption("fast-heartbeat", "Change stats polling interval from 10000ms to 1000ms.");
QCommandLineOption fastHeartbeatOption( QCommandLineOption logOption("logOptions",
"fast-heartbeat", "Logging options, comma separated: "
"Change stats polling interval from 10000ms to 1000ms." "color,nocolor,process_id,thread_id,milliseconds,keep_repeats,journald,nojournald",
); "options");
QCommandLineOption logOption(
"logOptions",
"Logging options, comma separated: color,nocolor,process_id,thread_id,milliseconds,keep_repeats,journald,nojournald",
"options"
);
// "--qmljsdebugger", which appears in output from "--help-all". // "--qmljsdebugger", which appears in output from "--help-all".
// Those below don't seem to be optional. // Those below don't seem to be optional.
// --ignore-gpu-blacklist // --ignore-gpu-blacklist
@ -296,7 +205,7 @@ int main(int argc, const char* argv[]) {
{ {
QCoreApplication tempApp(argc, const_cast<char**>(argv)); QCoreApplication tempApp(argc, const_cast<char**>(argv));
parser.process(QCoreApplication::arguments()); // Must be run after QCoreApplication is initalised. parser.process(QCoreApplication::arguments()); // Must be run after QCoreApplication is initalised.
#ifdef Q_OS_OSX #ifdef Q_OS_OSX
if (QFileInfo::exists(QCoreApplication::applicationDirPath() + "/../../../config.json")) { if (QFileInfo::exists(QCoreApplication::applicationDirPath() + "/../../../config.json")) {
@ -310,10 +219,10 @@ int main(int argc, const char* argv[]) {
} }
// We want to configure the logging system as early as possible // We want to configure the logging system as early as possible
auto &logHandler = LogHandler::getInstance(); auto& logHandler = LogHandler::getInstance();
if (parser.isSet(logOption)) { if (parser.isSet(logOption)) {
if (!logHandler.parseOptions(parser.value(logOption).toUtf8(), logOption.names().first())) { if (!logHandler.parseOptions(parser.value(logOption).toUtf8(), logOption.names().first())) {
QCoreApplication mockApp(argc, const_cast<char**>(argv)); // required for call to showHelp() QCoreApplication mockApp(argc, const_cast<char**>(argv)); // required for call to showHelp()
parser.showHelp(); parser.showHelp();
Q_UNREACHABLE(); Q_UNREACHABLE();
} }
@ -325,7 +234,7 @@ int main(int argc, const char* argv[]) {
Q_UNREACHABLE(); Q_UNREACHABLE();
} }
if (parser.isSet(helpOption)) { if (parser.isSet(helpOption)) {
QCoreApplication mockApp(argc, const_cast<char**>(argv)); // required for call to showHelp() QCoreApplication mockApp(argc, const_cast<char**>(argv)); // required for call to showHelp()
parser.showHelp(); parser.showHelp();
Q_UNREACHABLE(); Q_UNREACHABLE();
} }
@ -378,7 +287,7 @@ int main(int argc, const char* argv[]) {
// Early check for --traceFile argument // Early check for --traceFile argument
auto tracer = DependencyManager::set<tracing::Tracer>(); auto tracer = DependencyManager::set<tracing::Tracer>();
const char * traceFile = nullptr; const char* traceFile = nullptr;
float traceDuration = 0.0f; float traceDuration = 0.0f;
if (parser.isSet(traceFileOption)) { if (parser.isSet(traceFileOption)) {
traceFile = parser.value(traceFileOption).toStdString().c_str(); traceFile = parser.value(traceFileOption).toStdString().c_str();
@ -412,6 +321,8 @@ int main(int argc, const char* argv[]) {
// Instance UserActivityLogger now that the settings are loaded // Instance UserActivityLogger now that the settings are loaded
auto& ual = UserActivityLogger::getInstance(); auto& ual = UserActivityLogger::getInstance();
auto& ch = CrashHandler::getInstance();
// once the settings have been loaded, check if we need to flip the default for UserActivityLogger // once the settings have been loaded, check if we need to flip the default for UserActivityLogger
if (!ual.isDisabledSettingSet()) { if (!ual.isDisabledSettingSet()) {
// the user activity logger is opt-out for Interface // the user activity logger is opt-out for Interface
@ -423,13 +334,12 @@ int main(int argc, const char* argv[]) {
if (parser.isSet(forceCrashReportingOption)) { if (parser.isSet(forceCrashReportingOption)) {
qInfo() << "Crash reporting enabled on the command-line"; qInfo() << "Crash reporting enabled on the command-line";
ual.setCrashReportingEnabled(true); ch.setEnabled(true);
} }
auto crashHandlerStarted = startCrashHandler(argv[0]); auto crashHandlerStarted = ch.start(argv[0]);
if (crashHandlerStarted) { if (crashHandlerStarted) {
ual.setCrashMonitorStarted(true); qDebug() << "Crash handler started";
qDebug() << "Crash handler started:" << crashHandlerStarted;
} else { } else {
qWarning() << "Crash handler failed to start"; qWarning() << "Crash handler failed to start";
} }
@ -472,9 +382,9 @@ int main(int argc, const char* argv[]) {
if (socket.waitForConnected(LOCAL_SERVER_TIMEOUT_MS)) { if (socket.waitForConnected(LOCAL_SERVER_TIMEOUT_MS)) {
if (parser.isSet(urlOption)) { if (parser.isSet(urlOption)) {
QUrl url = QUrl(parser.value(urlOption)); QUrl url = QUrl(parser.value(urlOption));
if (url.isValid() && (url.scheme() == URL_SCHEME_OVERTE || url.scheme() == URL_SCHEME_OVERTEAPP if (url.isValid() && (url.scheme() == URL_SCHEME_OVERTE || url.scheme() == URL_SCHEME_OVERTEAPP ||
|| url.scheme() == HIFI_URL_SCHEME_HTTP || url.scheme() == HIFI_URL_SCHEME_HTTPS url.scheme() == HIFI_URL_SCHEME_HTTP || url.scheme() == HIFI_URL_SCHEME_HTTPS ||
|| url.scheme() == HIFI_URL_SCHEME_FILE)) { url.scheme() == HIFI_URL_SCHEME_FILE)) {
qDebug() << "Writing URL to local socket"; qDebug() << "Writing URL to local socket";
socket.write(url.toString().toUtf8()); socket.write(url.toString().toUtf8());
if (!socket.waitForBytesWritten(5000)) { if (!socket.waitForBytesWritten(5000)) {
@ -495,7 +405,6 @@ int main(int argc, const char* argv[]) {
#endif #endif
} }
// FIXME this method of checking the OpenGL version screws up the `QOpenGLContext::globalShareContext()` value, which in turn // FIXME this method of checking the OpenGL version screws up the `QOpenGLContext::globalShareContext()` value, which in turn
// leads to crashes when creating the real OpenGL instance. Disabling for now until we come up with a better way of checking // leads to crashes when creating the real OpenGL instance. Disabling for now until we come up with a better way of checking
// the GL version on the system without resorting to creating a full Qt application // the GL version on the system without resorting to creating a full Qt application
@ -522,7 +431,6 @@ int main(int argc, const char* argv[]) {
} }
#endif #endif
// Debug option to demonstrate that the client's local time does not // Debug option to demonstrate that the client's local time does not
// need to be in sync with any other network node. This forces clock // need to be in sync with any other network node. This forces clock
// skew for the individual client // skew for the individual client
@ -590,7 +498,8 @@ int main(int argc, const char* argv[]) {
#if defined(Q_OS_LINUX) #if defined(Q_OS_LINUX)
app.setWindowIcon(QIcon(PathUtils::resourcesPath() + "images/brand-logo.svg")); app.setWindowIcon(QIcon(PathUtils::resourcesPath() + "images/brand-logo.svg"));
#endif #endif
startCrashHookMonitor(&app); ch.startMonitor(&app);
QTimer exitTimer; QTimer exitTimer;
if (traceDuration > 0.0f) { if (traceDuration > 0.0f) {
@ -618,14 +527,14 @@ int main(int argc, const char* argv[]) {
#endif #endif
// Setup local server // Setup local server
QLocalServer server { &app }; QLocalServer server{ &app };
// We failed to connect to a local server, so we remove any existing servers. // We failed to connect to a local server, so we remove any existing servers.
server.removeServer(applicationName); server.removeServer(applicationName);
server.listen(applicationName); server.listen(applicationName);
QObject::connect(&server, &QLocalServer::newConnection, QObject::connect(&server, &QLocalServer::newConnection, &app, &Application::handleLocalServerConnection,
&app, &Application::handleLocalServerConnection, Qt::DirectConnection); Qt::DirectConnection);
printSystemInformation(); printSystemInformation();

View file

@ -5,13 +5,6 @@ link_hifi_libraries(shared networking)
add_crashpad() add_crashpad()
target_breakpad() target_breakpad()
if (UNIX AND NOT APPLE)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(Threads::Threads)
endif()
if (WIN32) if (WIN32)
add_compile_definitions(_USE_MATH_DEFINES) add_compile_definitions(_USE_MATH_DEFINES)
endif() endif()

View file

@ -0,0 +1,61 @@
//
// CrashHandler.cpp
//
//
// Created by Dale Glass on 25/06/2023.
// Copyright 2023 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "CrashHandler.h"
#include "CrashHandlerBackend.h"
CrashHandler& CrashHandler::getInstance() {
static CrashHandler sharedInstance;
return sharedInstance;
}
bool CrashHandler::start(const QString &path) {
if (isStarted()) {
qCWarning(crash_handler) << "Crash handler already started";
return false;
}
auto started = startCrashHandler(path.toStdString());
setStarted(started);
if ( started ) {
qCInfo(crash_handler) << "Crash handler started";
} else {
qCWarning(crash_handler) << "Crash handler failed to start";
}
return started;
}
void CrashHandler::startMonitor(QCoreApplication *app) {
startCrashHookMonitor(app);
}
void CrashHandler::setEnabled(bool enabled) {
if (enabled != _crashReportingEnabled.get()) {
_crashReportingEnabled.set(enabled);
setCrashReportingEnabled(enabled);
}
}
void CrashHandler::setAnnotation(const std::string &key, const char *value) {
setCrashAnnotation(key, std::string(value));
}
void CrashHandler::setAnnotation(const std::string &key, const QString &value) {
setCrashAnnotation(key, value.toStdString());
}
void CrashHandler::setAnnotation(const std::string &key, const std::string &value) {
setCrashAnnotation(key, value);
}

View file

@ -1,27 +1,107 @@
// //
// CrashHandler.h // CrashHandler.cpp
// interface/src
// //
// Created by Clement Brisset on 01/19/18. //
// Copyright 2018 High Fidelity, Inc. // Created by Dale Glass on 25/06/2023.
// Copyright 2023 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#ifndef hifi_CrashHandler_h #pragma once
#define hifi_CrashHandler_h
#include <string> #include <QObject>
#include <QCoreApplication> #include <QCoreApplication>
#include <QLoggingCategory> #include <SettingHandle.h>
Q_DECLARE_LOGGING_CATEGORY(crash_handler)
bool startCrashHandler(std::string appPath);
void setCrashAnnotation(std::string name, std::string value); /**
void startCrashHookMonitor(QCoreApplication* app); * @brief The global object in charge of setting up and controlling crash reporting.
void setCrashReportingEnabled(bool value); *
* This object initializes and talks to crash reporting backends.
*
*/
class CrashHandler : public QObject {
Q_OBJECT
public:
static CrashHandler& getInstance();
public slots:
/**
* @brief Start the crash handler
*
* @param path Database path
* @return true Started successfully
* @return false Failed to start
*/
bool start(const QString &path);
void startMonitor(QCoreApplication *app);
/**
* @brief Whether the crash monitor has been successfully started
*
* Reasons for it failing to start include:
*
* * Not having a crash reporter for the platform
* * Crash reporter not being configured with reporting URLs (CMAKE_BACKTRACE_TOKEN and CMAKE_BACKTRACE_URL)
* * Crash reporter is present and configured, but failed to initialize for some reason
*
* @return true Crash reporter is present, configured and working.
* @return false Crash reporter has not been started for one of the above reasons.
*/
bool isStarted() const { return _crashMonitorStarted; }
/**
* @brief Whether the crash monitor will report crashes if they occur
*
* This setting is independent of isCrashMonitorStarted() -- crash reporting may be enabled but fail to work
* due to the crash reporting component being missing or failing to initialize.
*
* @return true Crashes will be reported to CMAKE_BACKTRACE_URL
* @return false Crashes will not be reported
*/
bool isEnabled() const { return _crashReportingEnabled.get(); }
/**
* @brief Set whether we want to submit crash reports to the report server
*
* The report server is configured with CMAKE_BACKTRACE_URL.
* Emits crashReportingEnabledChanged signal.
*
* @param enabled Whether it's enabled.
*/
void setEnabled(bool enabled);
void setAnnotation(const std::string &key, const char *value);
void setAnnotation(const std::string &key, const QString &value);
void setAnnotation(const std::string &key, const std::string &value);
private:
/**
* @brief Marks the crash monitor as started
*
* @warning Only to be used as part of the startup process
*
* @param started
*/
void setStarted(bool started) { _crashMonitorStarted = started; }
Setting::Handle<bool> _crashReportingEnabled { "CrashReportingEnabled", false };
bool _crashMonitorStarted {false};
};
#endif // hifi_CrashHandler_h

View file

@ -0,0 +1,27 @@
//
// CrashHandler.h
// interface/src
//
// Created by Clement Brisset on 01/19/18.
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_CrashHandlerBackend_h
#define hifi_CrashHandlerBackend_h
#include <string>
#include <QCoreApplication>
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(crash_handler)
bool startCrashHandler(std::string appPath);
void setCrashAnnotation(std::string name, std::string value);
void startCrashHookMonitor(QCoreApplication* app);
void setCrashReportingEnabled(bool value);
#endif // hifi_CrashHandlerBackend_h

View file

@ -421,12 +421,12 @@ bool startCrashHandler(std::string appPath) {
} }
// Enable automated uploads. // Enable automated uploads.
QObject::connect(&UserActivityLogger::getInstance(), &UserActivityLogger::crashReportingEnabledChanged, []() { // QObject::connect(&UserActivityLogger::getInstance(), &UserActivityLogger::crashReportingEnabledChanged, []() {
auto &ual = UserActivityLogger::getInstance(); // auto &ual = UserActivityLogger::getInstance();
setCrashReportingEnabled(ual.isCrashReportingEnabled()); // setCrashReportingEnabled(ual.isCrashReportingEnabled());
}); // });
crashpadDatabase->GetSettings()->SetUploadsEnabled(UserActivityLogger::getInstance().isCrashReportingEnabled()); crashpadDatabase->GetSettings()->SetUploadsEnabled(CrashHandler::getInstance().isEnabled());
if (!client->StartHandler(handler, db, db, BACKTRACE_URL, annotations, arguments, true, true)) { if (!client->StartHandler(handler, db, db, BACKTRACE_URL, annotations, arguments, true, true)) {

View file

@ -82,15 +82,6 @@ void UserActivityLogger::requestError(QNetworkReply* errorReply) {
qCDebug(networking) << errorReply->error() << "-" << errorReply->errorString(); qCDebug(networking) << errorReply->error() << "-" << errorReply->errorString();
} }
void UserActivityLogger::setCrashReportingEnabled(bool enabled) {
bool old = _crashReportingEnabled.get();
_crashReportingEnabled.set(enabled);
if (old != enabled) {
emit crashReportingEnabledChanged();
}
}
void UserActivityLogger::launch(QString applicationVersion, bool previousSessionCrashed, int previousSessionRuntime) { void UserActivityLogger::launch(QString applicationVersion, bool previousSessionCrashed, int previousSessionRuntime) {
const QString ACTION_NAME = "launch"; const QString ACTION_NAME = "launch";
QJsonObject actionDetails; QJsonObject actionDetails;

View file

@ -36,51 +36,6 @@ public slots:
bool isDisabledSettingSet() const { return _disabled.isSet(); } bool isDisabledSettingSet() const { return _disabled.isSet(); }
/**
* @brief Whether the crash monitor has been successfully started
*
* Reasons for it failing to start include:
*
* * Not having a crash reporter for the platform
* * Crash reporter not being configured with reporting URLs (CMAKE_BACKTRACE_TOKEN and CMAKE_BACKTRACE_URL)
* * Crash reporter is present and configured, but failed to initialize for some reason
*
* @return true Crash reporter is present, configured and working.
* @return false Crash reporter has not been started for one of the above reasons.
*/
bool isCrashMonitorStarted() const { return _crashMonitorStarted; }
/**
* @brief Whether the crash monitor will report crashes if they occur
*
* This setting is independent of isCrashMonitorStarted() -- crash reporting may be enabled but fail to work
* due to the crash reporting component being missing or failing to initialize.
*
* @return true Crashes will be reported to CMAKE_BACKTRACE_URL
* @return false Crashes will not be reported
*/
bool isCrashReportingEnabled() { return _crashReportingEnabled.get(); }
/**
* @brief Marks the crash monitor as started
*
* @warning Only to be used as part of the startup process
*
* @param started
*/
void setCrashMonitorStarted(bool started) { _crashMonitorStarted = started; }
/**
* @brief Set whether we want to submit crash reports to the report server
*
* The report server is configured with CMAKE_BACKTRACE_URL.
* Emits crashReportingEnabledChanged signal.
*
* @param enabled Whether it's enabled.
*/
void setCrashReportingEnabled(bool enabled);
void disable(bool disable); void disable(bool disable);
void logAction(QString action, QJsonObject details = QJsonObject(), JSONCallbackParameters params = JSONCallbackParameters()); void logAction(QString action, QJsonObject details = QJsonObject(), JSONCallbackParameters params = JSONCallbackParameters());
@ -111,9 +66,9 @@ private slots:
private: private:
UserActivityLogger(); UserActivityLogger();
Setting::Handle<bool> _disabled { "UserActivityLoggerDisabled", true }; Setting::Handle<bool> _disabled { "UserActivityLoggerDisabled", true };
Setting::Handle<bool> _crashReportingEnabled { "CrashReportingEnabled", false };
bool _crashMonitorStarted {false};
QElapsedTimer _timer; QElapsedTimer _timer;
}; };