fix Windows crashes dump upload on BugSplat #LINQT-2384

Try to fix deploy (symbols are not uploaded in deploy, only packaging works with cr)
This commit is contained in:
Gaelle Braud 2026-02-09 17:21:20 +01:00 committed by gaelle
parent bf786c67a3
commit 7e0a33766b
16 changed files with 941 additions and 881 deletions

View file

@ -102,7 +102,7 @@ macosx-ninja-package:
- if: $PACKAGE_MACOSX - if: $PACKAGE_MACOSX
- if: $DEPLOY_MACOSX - if: $DEPLOY_MACOSX
variables: variables:
CMAKE_OPTIONS: -DPython3_ROOT_DIR=/opt/bc/pip-packages/ -DENABLE_APP_PACKAGING=ON -DENABLE_GPL_THIRD_PARTIES=OFF -DENABLE_G729=ON -DENABLE_BUGSPLAT_SYMBOLS_UPLOAD=ON -DBUGSPLAT_CLIENT_ID=$BUGSPLAT_CLIENT_ID -DBUGSPLAT_CLIENT_SECRET=$BUGSPLAT_CLIENT_SECRET -DBUGSPLAT_DATABASE=$BUGSPLAT_DATABASE CMAKE_OPTIONS: -DPython3_ROOT_DIR=/opt/bc/pip-packages/ -DENABLE_APP_PACKAGING=ON -DENABLE_GPL_THIRD_PARTIES=OFF -DENABLE_G729=ON -DBUGSPLAT_CLIENT_ID=$BUGSPLAT_CLIENT_ID -DBUGSPLAT_CLIENT_SECRET=$BUGSPLAT_CLIENT_SECRET -DBUGSPLAT_DATABASE=$BUGSPLAT_DATABASE
RELEASE_FILE: -DLINPHONE_SDK_MAKE_RELEASE_FILE_URL=$MAKE_RELEASE_FILE_URL/$MACOSX_PLATFORM/$APP_FOLDER RELEASE_FILE: -DLINPHONE_SDK_MAKE_RELEASE_FILE_URL=$MAKE_RELEASE_FILE_URL/$MACOSX_PLATFORM/$APP_FOLDER
extends: macosx-ninja extends: macosx-ninja
script: script:

View file

@ -182,20 +182,20 @@ win64-ninja-vs2022-scheduled-windows:
- !reference [.rules-merge-request-manual, rules] - !reference [.rules-merge-request-manual, rules]
- if: $NIGHTLY_RELEASE - if: $NIGHTLY_RELEASE
- if: $PACKAGE_WINDOWS - if: $PACKAGE_WINDOWS
variables:
CMAKE_OPTIONS: -DENABLE_APP_PACKAGING=YES -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=OFF
RELEASE_FILE: -DLINPHONE_SDK_MAKE_RELEASE_FILE_URL=$MAKE_RELEASE_FILE_URL/$WINDOWS_PLATFORM/$APP_FOLDER
.vs-win64-package-cr:
stage: package
needs: []
rules:
- if: $NIGHTLY_MASTER
- if: $DEPLOY_WINDOWS
variables: variables:
CMAKE_OPTIONS: -DENABLE_APP_PACKAGING=YES -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=OFF -DENABLE_BUGSPLAT_SYMBOLS_UPLOAD=ON -DBUGSPLAT_CLIENT_ID=$BUGSPLAT_CLIENT_ID -DBUGSPLAT_CLIENT_SECRET=$BUGSPLAT_CLIENT_SECRET -DBUGSPLAT_DATABASE=$BUGSPLAT_DATABASE CMAKE_OPTIONS: -DENABLE_APP_PACKAGING=YES -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=OFF -DENABLE_BUGSPLAT_SYMBOLS_UPLOAD=ON -DBUGSPLAT_CLIENT_ID=$BUGSPLAT_CLIENT_ID -DBUGSPLAT_CLIENT_SECRET=$BUGSPLAT_CLIENT_SECRET -DBUGSPLAT_DATABASE=$BUGSPLAT_DATABASE
RELEASE_FILE: -DLINPHONE_SDK_MAKE_RELEASE_FILE_URL=$MAKE_RELEASE_FILE_URL/$WINDOWS_PLATFORM/$APP_FOLDER RELEASE_FILE: -DLINPHONE_SDK_MAKE_RELEASE_FILE_URL=$MAKE_RELEASE_FILE_URL/$WINDOWS_PLATFORM/$APP_FOLDER
# .vs-win64-package-cr:
# stage: package
# needs: []
# rules:
# - if: $NIGHTLY_MASTER
# - if: $DEPLOY_WINDOWS
# variables:
# CMAKE_OPTIONS: -DENABLE_APP_PACKAGING=YES -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=OFF -DENABLE_BUGSPLAT_SYMBOLS_UPLOAD=ON -DBUGSPLAT_CLIENT_ID=$BUGSPLAT_CLIENT_ID -DBUGSPLAT_CLIENT_SECRET=$BUGSPLAT_CLIENT_SECRET -DBUGSPLAT_DATABASE=$BUGSPLAT_DATABASE
# RELEASE_FILE: -DLINPHONE_SDK_MAKE_RELEASE_FILE_URL=$MAKE_RELEASE_FILE_URL/$WINDOWS_PLATFORM/$APP_FOLDER
win64-ninja-vs2022-package-windows: win64-ninja-vs2022-package-windows:
variables: variables:
CMAKE_GENERATOR: "Ninja" CMAKE_GENERATOR: "Ninja"
@ -207,15 +207,15 @@ win64-ninja-vs2022-package-windows:
- .vs-win64-package - .vs-win64-package
#Packaging for deployment (Upload symbols at the same time of the packaging) #Packaging for deployment (Upload symbols at the same time of the packaging)
win64-ninja-vs2022-package-cr-windows: # win64-ninja-vs2022-package-cr-windows:
variables: # variables:
CMAKE_GENERATOR: "Ninja" # CMAKE_GENERATOR: "Ninja"
CMAKE_ARCHITECTURE: "" # CMAKE_ARCHITECTURE: ""
PARALLEL_OPTIONS: "" # PARALLEL_OPTIONS: ""
extends: # extends:
- .windows-vs2022 # - .windows-vs2022
- .windows-ninja-variables # - .windows-ninja-variables
- .vs-win64-package-cr # - .vs-win64-package-cr
################################################# #################################################
@ -244,28 +244,6 @@ win64-codesigning:
when: always when: always
expire_in: 1 week expire_in: 1 week
win64-codesigning-cr:
stage: signing
allow_failure: true
extends:
- .windows-codesigning
needs:
- win64-ninja-vs2022-package-cr-windows
variables:
MINGW_TYPE: mingw64
rules:
- if: $NIGHTLY_MASTER
- if: $DEPLOY_WINDOWS
script:
- cd build-desktop/OUTPUT/Packages/
- Invoke-Expression "& ${WINDOWS_SIGN_TOOL} sign /fd SHA256 /t ${WINDOWS_SIGN_TIMESTAMP_URL} /sha1 ${WINDOWS_SIGN_HASH} *.exe"
- 'if (-not ($LastExitCode -eq 0)) {throw "Error: Signature failed"}'
artifacts:
paths:
- build-desktop\OUTPUT\Packages\*
when: always
expire_in: 1 week
################################################# #################################################
# DEPLOY # DEPLOY
################################################# #################################################
@ -286,7 +264,7 @@ win64-ninja-vs2022-upload:
extends: extends:
- .win64-upload - .win64-upload
needs: needs:
- win64-codesigning-cr - win64-codesigning
.win64-plugins-upload: .win64-plugins-upload:
stage: deploy stage: deploy

View file

@ -244,7 +244,10 @@ if(NOT APPLE OR MONO_ARCH)
add_external() add_external()
endif() endif()
if(TARGET Crashpad) if(TARGET Crashpad)
message(DEBUG "Target Crashpad, enable crash handler")
set(HAVE_CRASH_HANDLER 1) set(HAVE_CRASH_HANDLER 1)
else()
message(DEBUG "Target is not Crashpad, disable crash handler")
endif() endif()
function(add_linphone_app) function(add_linphone_app)
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) # Prevent project from overriding the options we just set here set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) # Prevent project from overriding the options we just set here

View file

@ -312,8 +312,11 @@ App::App(int &argc, char *argv[])
mLinphoneThread = new Thread(this); mLinphoneThread = new Thread(this);
init(); init();
lInfo() << QStringLiteral("Starting application " APPLICATION_NAME " (bin: " EXECUTABLE_NAME lInfo() << QStringLiteral("Starting application %1 %2 %3 %4")
"). Version:%1 Os:%2 Qt:%3") .arg(APPLICATION_NAME)
.arg("(bin:")
.arg(EXECUTABLE_NAME)
.arg("). Version:%1 Os:%2 Qt:%3")
.arg(applicationVersion()) .arg(applicationVersion())
.arg(Utils::getOsProduct()) .arg(Utils::getOsProduct())
.arg(qVersion()); .arg(qVersion());
@ -664,6 +667,17 @@ void App::initCore() {
QMetaObject::invokeMethod(App::getInstance()->thread(), [this, settings] { QMetaObject::invokeMethod(App::getInstance()->thread(), [this, settings] {
// Initialize DestopTools here to have logs into files in case of errors. // Initialize DestopTools here to have logs into files in case of errors.
DesktopTools::init(); DesktopTools::init();
// CrashReporter must be call after app initialization like names.
#ifdef HAVE_CRASH_HANDLER
lInfo() << log().arg("Start CrashReporter.");
bool status = CrashReporter::start();
if (!status) {
lWarning() << log().arg("CrashReporter could not start.");
}
#else
lWarning() << "[Main] The application doesn't support the CrashReporter.";
#endif
// QML // QML
mEngine = new QQmlApplicationEngine(this); mEngine = new QQmlApplicationEngine(this);
assert(mEngine); assert(mEngine);

View file

@ -296,6 +296,15 @@ QString Paths::getCrashpadDirPath() {
#endif #endif
} }
QString Paths::getCrashpadAttachmentsPath() {
#ifdef HAVE_CRASH_HANDLER
return getWritableDirPath(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) +
Constants::PathCrashpadAttachments);
#else
return "";
#endif
}
QString Paths::getMetricsDirPath() { QString Paths::getMetricsDirPath() {
return getWritableDirPath(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + return getWritableDirPath(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) +
Constants::PathMetrics); Constants::PathMetrics);

View file

@ -44,6 +44,7 @@ QString getFriendsListFilePath();
QString getLimeDatabasePath(); QString getLimeDatabasePath();
QString getLogsDirPath(); QString getLogsDirPath();
QString getCrashpadDirPath(); QString getCrashpadDirPath();
QString getCrashpadAttachmentsPath();
QString getMetricsDirPath(); QString getMetricsDirPath();
QString getMessageHistoryFilePath(); QString getMessageHistoryFilePath();
QString getPackageDataDirPath(); QString getPackageDataDirPath();

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -158,8 +158,9 @@ public:
static constexpr char PathUserCertificates[] = "/usr-crt/"; static constexpr char PathUserCertificates[] = "/usr-crt/";
#ifdef HAVE_CRASH_HANDLER #ifdef HAVE_CRASH_HANDLER
static constexpr char PathCrashpad[] = "/crashpad/"; static constexpr char PathCrashpad[] = "/crashpad/";
static constexpr char PathCrashpadAttachments[] = "/crashpad/attachments/";
static constexpr char PathCrashpadHandler[] = CRASHPAD_EXECUTABLE_NAME; static constexpr char PathCrashpadHandler[] = CRASHPAD_EXECUTABLE_NAME;
static constexpr char BugsplatUrl[] = "https://Linphone.bugsplat.com/post/bp/crash/crashpad.php"; static constexpr char BugsplatUrl[] = "https://" BUGSPLAT_DATABASE ".bugsplat.com/post/bp/crash/crashpad.php";
#endif #endif
static constexpr char PathCallHistoryList[] = "/call-history.db"; static constexpr char PathCallHistoryList[] = "/call-history.db";

View file

@ -39,6 +39,7 @@
#include "tool/providers/AvatarProvider.hpp" #include "tool/providers/AvatarProvider.hpp"
#include <limits.h> #include <limits.h>
#include <signal.h>
#include <QClipboard> #include <QClipboard>
#include <QCryptographicHash> #include <QCryptographicHash>
@ -2206,3 +2207,9 @@ bool Utils::stringMatchFormat(QString toMatch, QRegularExpression regExp) {
auto match = regExp.match(toMatch); auto match = regExp.match(toMatch);
return match.hasMatch(); return match.hasMatch();
} }
// Debug
void Utils::forceCrash() {
lInfo() << "throwing segmentation fault for debug";
raise(SIGSEGV);
}

View file

@ -192,6 +192,9 @@ public:
Q_INVOKABLE static bool stringMatchFormat(QString toMatch, QRegularExpression regExp); Q_INVOKABLE static bool stringMatchFormat(QString toMatch, QRegularExpression regExp);
// Debug
Q_INVOKABLE static void forceCrash();
// QDir findDirectoryByName(QString startPath, QString name); // QDir findDirectoryByName(QString startPath, QString name);
static QString getApplicationProduct(); static QString getApplicationProduct();

View file

@ -20,20 +20,18 @@
#include "CrashReporter.hpp" #include "CrashReporter.hpp"
#include "config.h" #include "config.h"
#include "tool/Utils.hpp"
#include "tool/Constants.hpp"
#include "core/path/Paths.hpp" #include "core/path/Paths.hpp"
#include "model/setting/SettingsModel.hpp" #include "model/setting/SettingsModel.hpp"
#include "tool/Constants.hpp"
#include "tool/Utils.hpp"
#include "client/crash_report_database.h" #include "client/crash_report_database.h"
#include "client/settings.h" #include "client/settings.h"
#include <QSettings> #include <QSettings>
CrashReporter *CrashReporter::gHandler = nullptr;
CrashReporter* CrashReporter::gHandler = nullptr; CrashReporter::CrashReporter(QObject *parent) : QObject(parent) {
CrashReporter::CrashReporter(QObject * parent): QObject(parent) {
mHandlerPath = base::FilePath(Utils::getNativeString(Paths::getCrashpadHandlerFilePath())); mHandlerPath = base::FilePath(Utils::getNativeString(Paths::getCrashpadHandlerFilePath()));
mDatabasePath = base::FilePath(Utils::getNativeString(Paths::getCrashpadDirPath())); mDatabasePath = base::FilePath(Utils::getNativeString(Paths::getCrashpadDirPath()));
mMetricsPath = base::FilePath(Utils::getNativeString(Paths::getMetricsDirPath())); mMetricsPath = base::FilePath(Utils::getNativeString(Paths::getMetricsDirPath()));
@ -49,42 +47,69 @@ CrashReporter::CrashReporter(QObject * parent): QObject(parent) {
// Disable crashpad rate limiting so that all crashes have dmp files // Disable crashpad rate limiting so that all crashes have dmp files
mArguments.push_back("--no-rate-limit"); mArguments.push_back("--no-rate-limit");
auto config = linphone::Factory::get()->createConfig(Utils::appStringToCoreString(Paths::getConfigFilePath("", true))); auto config =
linphone::Factory::get()->createConfig(Utils::appStringToCoreString(Paths::getConfigFilePath("", true)));
// Attachments to be uploaded alongside the crash - default bundle size limit is 20MB // Attachments to be uploaded alongside the crash - default bundle size limit is 20MB
// Crashpad doesn't manage folders. We have to guess the files to be uploaded. // Crashpad doesn't manage folders. We have to guess the files to be uploaded.
QString logFiles = Paths::getLogsDirPath()+QDir::separator()+EXECUTABLE_NAME; QString logFiles = Paths::getLogsDirPath() + QDir::separator() + EXECUTABLE_NAME;
mAttachments.push_back(base::FilePath(Utils::getNativeString(logFiles+".log"))); mAttachments.push_back(base::FilePath(Utils::getNativeString(logFiles + ".log")));
mAttachments.push_back(base::FilePath(Utils::getNativeString(logFiles + "1.log"))); mAttachments.push_back(base::FilePath(Utils::getNativeString(logFiles + "1.log")));
mAttachments.push_back(base::FilePath(Utils::getNativeString(logFiles + "2.log"))); mAttachments.push_back(base::FilePath(Utils::getNativeString(logFiles + "2.log")));
} }
void CrashReporter::start() { bool CrashReporter::start() {
auto config = linphone::Factory::get()->createConfig(Utils::appStringToCoreString(Paths::getConfigFilePath("", true))); lInfo() << "[CrashReporter] Starting CrashReporter";
CrashReporter::enable(SettingsModel::getCrashReporterEnabled(config)); auto config =
linphone::Factory::get()->createConfig(Utils::appStringToCoreString(Paths::getConfigFilePath("", true)));
return CrashReporter::enable(SettingsModel::getCrashReporterEnabled(config));
} }
void CrashReporter::run() { bool CrashReporter::run() {
//crashpad::CrashpadClient *client = new crashpad::CrashpadClient();
bool status = mClient.StartHandler(mHandlerPath, mDatabasePath, mMetricsPath, mBugsplatUrl.toStdString(), mAnnotations.toStdMap(), mArguments, true, true, mAttachments);
if(!status){ // Attachments to be uploaded alongside the crash - default bundle size limit is 20MB
base::FilePath attachment(Utils::getNativeString(Paths::getCrashpadAttachmentsPath()));
#if defined(Q_OS_WINDOWS) || defined(Q_OS_LINUX)
// Crashpad hasn't implemented attachments on OS X yet
mAttachments.push_back(attachment);
#endif
lInfo() << "[CrashReporter] Start handler, handler path =" << Paths::getCrashpadHandlerFilePath()
<< "| database path =" << Paths::getCrashpadDirPath() << "| metrics path =" << Paths::getMetricsDirPath()
<< "bugsplat url =" << mBugsplatUrl;
// crashpad::CrashpadClient *client = new crashpad::CrashpadClient();
bool status = mClient.StartHandler(mHandlerPath, mDatabasePath, mMetricsPath, mBugsplatUrl.toStdString(),
mAnnotations.toStdMap(), mArguments, true, true, mAttachments);
if (!status) {
lWarning() << "[CrashReporter] Failed to start Crashpad handler. Crashes will not be logged."; lWarning() << "[CrashReporter] Failed to start Crashpad handler. Crashes will not be logged.";
} else { } else {
lInfo() << "[CrashReporter] Started Crashpad handler. Database at " << Paths::getCrashpadDirPath(); lInfo() << "[CrashReporter] Started Crashpad handler. Database at" << Paths::getCrashpadDirPath();
lInfo() << "[CrashReporter] Crashes upload url :" << mBugsplatUrl;
} }
return status;
} }
void CrashReporter::enable(const bool& on) { bool CrashReporter::enable(const bool &on) {
if(!gHandler) gHandler = new CrashReporter(); if (!gHandler) gHandler = new CrashReporter();
std::unique_ptr<crashpad::CrashReportDatabase> database = crashpad::CrashReportDatabase::Initialize(gHandler->mDatabasePath); lInfo() << "[CrashReporter] Enable CrashReporter" << on;
if (database == NULL) return; std::unique_ptr<crashpad::CrashReportDatabase> database =
crashpad::CrashReportDatabase::Initialize(gHandler->mDatabasePath);
if (database == NULL) {
lInfo() << "[CrashReporter] No Crashpad database, return";
return false;
}
crashpad::Settings *settings = database->GetSettings(); crashpad::Settings *settings = database->GetSettings();
if (settings == NULL) return; if (settings == NULL) {
lInfo() << "[CrashReporter] No Crashpad settings, return";
return false;
}
settings->SetUploadsEnabled(on); settings->SetUploadsEnabled(on);
if(on) gHandler->run();
else { if (on) {
lInfo() << "[CrashReporter] Run Crashpad";
return gHandler->run();
} else {
lInfo() << "[CrashReporter] Crashpad has been deactivated by user."; lInfo() << "[CrashReporter] Crashpad has been deactivated by user.";
return false;
} }
} }

View file

@ -21,21 +21,21 @@
#ifndef CRASH_REPORTER_H_ #ifndef CRASH_REPORTER_H_
#define CRASH_REPORTER_H_ #define CRASH_REPORTER_H_
#include <QObject>
#include <QMap> #include <QMap>
#include <QObject>
#include <QVector> #include <QVector>
#include <string> #include <string>
#include "client/crashpad_client.h" #include "client/crashpad_client.h"
// ============================================================================= // =============================================================================
class CrashReporter : public QObject{ class CrashReporter : public QObject {
public: public:
CrashReporter(QObject * parent = nullptr); CrashReporter(QObject *parent = nullptr);
static void start(); static bool start();
static void enable(const bool& on); static bool enable(const bool &on);
void run(); bool run();
crashpad::CrashpadClient mClient; crashpad::CrashpadClient mClient;
std::vector<base::FilePath> mAttachments; std::vector<base::FilePath> mAttachments;
@ -46,7 +46,7 @@ public:
base::FilePath mMetricsPath; base::FilePath mMetricsPath;
base::FilePath mLogsPath; base::FilePath mLogsPath;
QString mBugsplatUrl; QString mBugsplatUrl;
static CrashReporter* gHandler; static CrashReporter *gHandler;
}; };
#endif #endif

View file

@ -568,6 +568,23 @@ Item {
} }
} }
} }
MouseArea {
z: parent.z + 1
anchors.fill: parent
acceptedButtons: Qt.RightButton
onPressAndHold: (mouse) => {
debugPopup.open()
}
PopupButton {
id: debugPopup
visible: false
popup.contentItem: Button {
text: "debug: force crash"
onClicked: UtilsCpp.forceCrash()
}
}
}
} }
} }
} }

View file

@ -171,6 +171,8 @@ if(HAVE_CRASH_HANDLER)
endif() endif()
endif() endif()
endif() endif()
else()
message(DEBUG "No Crash handler, do not configure Crashpad")
endif() endif()
# ============================================================================== # ==============================================================================