1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-16 11:04:01 +02:00

* Added breakpad support for Linux.

This commit is contained in:
Christian Muehlhaeuser
2011-09-15 07:27:31 +02:00
parent d8b07cee9c
commit d8d7347394
1163 changed files with 465521 additions and 4 deletions

View File

@@ -1,7 +1,7 @@
SET( OS_SPECIFIC_LINK_LIBRARIES
${OS_SPECIFIC_LINK_LIBRARIES}
tomahawklib
# breakpad_client
tomahawk_breakpad
)
FILE( GLOB _icons "${CMAKE_SOURCE_DIR}/data/icons/tomahawk-icon-*.png" )

View File

@@ -63,6 +63,8 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
sourcetree/items/genericpageitems.cpp
sourcetree/items/temporarypageitem.cpp
breakpad/BreakPad.cpp
transferview.cpp
PipelineStatusView.cpp
tomahawktrayicon.cpp
@@ -113,6 +115,8 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui}
sourcetree/items/genericpageitems.h
sourcetree/items/temporarypageitem.h
breakpad/BreakPad.h
transferview.h
PipelineStatusView.h
tomahawktrayicon.h

126
src/breakpad/BreakPad.cpp Normal file
View File

@@ -0,0 +1,126 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include "BreakPad.h"
#include <QString>
#ifndef WIN32
#include <unistd.h>
#define CRASH_REPORTER_BINARY "CrashReporter"
static bool
LaunchUploader( const char* dump_dir, const char* minidump_id, void* that, bool succeeded )
{
// DON'T USE THE HEAP!!!
// So that indeed means, no QStrings, no qDebug(), no QAnything, seriously!
if ( !succeeded )
return false;
pid_t pid = fork();
if ( pid == -1 ) // fork failed
return false;
if ( pid == 0 )
{
// we are the fork
execl( CRASH_REPORTER_BINARY,
CRASH_REPORTER_BINARY,
dump_dir,
minidump_id,
minidump_id,
(char*) 0 );
// execl replaces this process, so no more code will be executed
// unless it failed. If it failed, then we should return false.
return false;
}
// we called fork()
return true;
}
BreakPad::BreakPad( const QString& path )
: google_breakpad::ExceptionHandler( path.toStdString(), 0, LaunchUploader, this, true )
{
}
#else
static bool
LaunchUploader( const wchar_t* dump_dir, const wchar_t* minidump_id, void* that, EXCEPTION_POINTERS *exinfo, MDRawAssertionInfo *assertion, bool succeeded )
{
if ( !succeeded )
return false;
// DON'T USE THE HEAP!!!
// So that indeed means, no QStrings, no qDebug(), no QAnything, seriously!
const char* m_product_name = static_cast<BreakPad*>(that)->productName();
// convert m_product_name to widechars, which sadly means the product name must be Latin1
wchar_t product_name[ 256 ];
char* out = (char*)product_name;
const char* in = m_product_name - 1;
do {
*out++ = *++in; //latin1 chars fit in first byte of each wchar
*out++ = '\0'; //every second byte is NULL
}
while (*in);
wchar_t command[MAX_PATH * 3 + 6];
wcscpy( command, CRASH_REPORTER_BINARY L" \"" );
wcscat( command, dump_dir );
wcscat( command, L"\" \"" );
wcscat( command, minidump_id );
wcscat( command, L"\" \"" );
wcscat( command, product_name );
wcscat( command, L"\"" );
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof( si ) );
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNORMAL;
ZeroMemory( &pi, sizeof(pi) );
if (CreateProcess( NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
TerminateProcess( GetCurrentProcess(), 1 );
}
return false;
}
BreakPad::BreakPad( const QString& path )
: google_breakpad::ExceptionHandler( path.toStdWString(), 0, LaunchUploader, this, true )
{
}
#endif // WIN32

43
src/breakpad/BreakPad.h Normal file
View File

@@ -0,0 +1,43 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QString>
#ifdef __APPLE__
# include "client/mac/handler/exception_handler.h"
#elif defined WIN32
# include "client/windows/handler/exception_handler.h"
#elif defined __linux__
# include "client/linux/handler/exception_handler.h"
#endif
class BreakPad : public google_breakpad::ExceptionHandler
{
const char* m_product_name; // yes! It MUST be const char[]
public:
BreakPad( const QString &dump_write_dirpath );
~BreakPad()
{}
void setProductName( const char* s ) { m_product_name = s; };
const char* productName() const { return m_product_name; }
};
#undef char

View File

@@ -0,0 +1,20 @@
PROJECT( CrashReporter )
FIND_PACKAGE( Qt4 REQUIRED )
SET( QT_USE_QTNETWORK TRUE )
SET( crashreporter_SOURCES main.cpp CrashReporter.cpp )
SET( crashreporter_HEADERS CrashReporter.h )
SET( crashreporter_UI CrashReporter.ui )
SET( crashreporter_RC ../../../resources.qrc )
QT4_WRAP_CPP( crashreporter_HEADERS_MOC ${crashreporter_HEADERS} )
QT4_WRAP_UI( crashreporter_UI_HEADERS ${crashreporter_UI} )
QT4_ADD_RESOURCES( crashreporter_RC_RCC ${crashreporter_RC} )
INCLUDE( ${QT_USE_FILE} )
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} )
ADD_DEFINITIONS( ${QT_DEFINITIONS} )
ADD_EXECUTABLE( CrashReporter ${crashreporter_SOURCES} ${crashreporter_HEADERS_MOC} ${crashreporter_UI_HEADERS} ${crashreporter_RC_RCC} )
TARGET_LINK_LIBRARIES( CrashReporter ${QT_LIBRARIES} )

View File

@@ -0,0 +1,183 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CrashReporter.h"
#include <QIcon>
#include <QDebug>
#include <QTimer>
#include <QDir>
#include <QDateTime>
#include <QHttp>
#define RESPATH ":/data/"
CrashReporter::CrashReporter( const QStringList& args )
{
setWindowIcon( QIcon( RESPATH "icons/tomahawk-icon-128x128.png" ) );
ui.setupUi( this );
ui.logoLabel->setPixmap( QPixmap( RESPATH "icons/tomahawk-icon-128x128.png" ).scaled( QSize( 55, 55 ), Qt::KeepAspectRatio, Qt::SmoothTransformation ) );
ui.progressBar->setRange( 0, 100 );
ui.progressBar->setValue( 0 );
ui.progressLabel->setPalette( Qt::gray );
#ifdef Q_WS_MAC
// macify++
QFont f = ui.bottomLabel->font();
f.setPointSize( 10 );
ui.bottomLabel->setFont( f );
f.setPointSize( 11 );
ui.progressLabel->setFont( f );
ui.progressLabel->setIndent( 3 );
#else
ui.vboxLayout->setSpacing( 16 );
ui.progressBar->setTextVisible( false );
ui.progressLabel->setIndent( 1 );
ui.bottomLabel->setDisabled( true );
ui.bottomLabel->setIndent( 1 );
// adjust the spacer since we adjusted the spacing above
for (int x = 0; x < ui.vboxLayout->count(); ++x)
if (QSpacerItem* spacer = ui.vboxLayout->itemAt( x )->spacerItem())
{
spacer->changeSize( 6, 2, QSizePolicy::Minimum, QSizePolicy::Fixed );
break;
}
#endif //Q_WS_MAC
m_http = new QHttp( "oops.tomahawk-player.org", 80, this );
connect( m_http, SIGNAL( done( bool ) ), SLOT( onDone() ), Qt::QueuedConnection );
connect( m_http, SIGNAL( dataSendProgress( int, int ) ), SLOT( onProgress( int, int ) ) );
m_dir = args.value( 1 );
m_minidump = m_dir + '/' + args.value( 2 ) + ".dmp";
m_product_name = args.value( 3 );
QTimer::singleShot( 0, this, SLOT(send()) );
setFixedSize( sizeHint() );
}
static QByteArray
contents( const QString& path )
{
QFile f( path );
f.open( QFile::ReadOnly );
return f.readAll();
}
void
CrashReporter::send()
{
QByteArray body;
// socorro expects a 10 digit build id
QRegExp rx( "(\\d+\\.\\d+\\.\\d+).(\\d+)" );
rx.exactMatch( "0.2.99" );
QString const version = rx.cap( 1 );
QString const buildId = rx.cap( 2 ).leftJustified( 10, '0' );
// add parameters
typedef QPair<QByteArray, QByteArray> Pair;
QList<Pair> pairs;
pairs << Pair( "BuildID", buildId.toUtf8() )
<< Pair( "ProductName", m_product_name.toUtf8() )
<< Pair( "Version", version.toUtf8() )
<< Pair( "Vendor", "Tomahawk" )
<< Pair( "timestamp", QByteArray::number( QDateTime::currentDateTime().toTime_t() ) );
foreach ( Pair const pair, pairs )
{
body += "--thkboundary\r\n";
body += "Content-Disposition: form-data; name=\"" +
pair.first + "\"\r\n\r\n" +
pair.second + "\r\n";
}
// add minidump file
body += "--thkboundary\r\n";
body += "Content-Disposition: form-data; name=\"upload_file_minidump\"; filename=\""
+ QFileInfo( m_minidump ).fileName() + "\"\r\n";
body += "Content-Type: application/octet-stream\r\n";
body += "\r\n";
body += contents( m_minidump );
body += "\r\n";
// add logfile
body += "--thkboundary\r\n";
body += "Content-Disposition: form-data; name=\"upload_file_containerlog\"; filename=\"container.log\"\r\n";
body += "Content-Type: application/x-gzip\r\n";
body += "\r\n";
// body += qCompress( contents( "Tomahawk.log" ) );
body += "\r\n";
body += "--thkboundary--\r\n";
//////
QHttpRequestHeader header( "POST", "/addreport.php" );
header.setContentType( "multipart/form-data; boundary=thkboundary" );
header.setValue( "HOST", "oops.tomahawk-player.org" );
m_http->request( header, body );
}
void
CrashReporter::onProgress( int done, int total )
{
if ( total )
{
QString const msg = tr( "Uploaded %L1 of %L2 KB." ).arg( done / 1024 ).arg( total / 1024 );
ui.progressBar->setMaximum( total );
ui.progressBar->setValue( done );
ui.progressLabel->setText( msg );
}
}
void
CrashReporter::onDone()
{
QByteArray data = m_http->readAll();
ui.progressBar->setValue( ui.progressBar->maximum() );
ui.button->setText( tr( "Close" ) );
QString const response = QString::fromUtf8( data );
if ( m_http->error() != QHttp::NoError || !response.startsWith( "CrashID=" ) )
{
onFail( m_http->error(), m_http->errorString() );
}
else
ui.progressLabel->setText( tr( "Sent! <b>Many thanks</b>." ) );
}
void
CrashReporter::onFail( int error, const QString& errorString )
{
ui.button->setText( tr( "Close" ) );
ui.progressLabel->setText( tr( "Failed to send crash info." ) );
qDebug() << "Error: " << error << errorString;
}

View File

@@ -0,0 +1,52 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CRASHREPORTER_H
#define CRASHREPORTER_H
#include <QDialog>
#include <QFile>
#include "ui_CrashReporter.h"
class CrashReporter : public QDialog
{
Q_OBJECT
public:
CrashReporter( const QStringList& argv );
private:
Ui::CrashReporter ui;
QString m_minidump;
QString m_dir;
QString m_product_name;
class QHttp* m_http;
public slots:
void send();
private slots:
void onDone();
void onProgress( int done, int total );
void onFail( int error, const QString& errorString );
};
#endif // CRASHREPORTER_H

View File

@@ -0,0 +1,223 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CrashReporter</class>
<widget class="QDialog" name="CrashReporter">
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>438</width>
<height>196</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Tomahawk Crash Reporter</string>
</property>
<property name="modal">
<bool>false</bool>
</property>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<number>9</number>
</property>
<item>
<layout class="QHBoxLayout">
<property name="spacing">
<number>12</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="logoLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>55</width>
<height>55</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>55</width>
<height>55</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="topLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;p&gt;&lt;b&gt;Sorry!&lt;/b&gt;&amp;nbsp;Tomahawk crashed. Information about the crash is now being sent to Tomahawk HQ so that we can fix the bug.&lt;/p&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>6</width>
<height>6</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>16</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="progressLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout">
<property name="spacing">
<number>9</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="value">
<number>24</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="button">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Abort</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="bottomLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>You can disable sending crash reports in the configuration dialog.</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>button</sender>
<signal>clicked()</signal>
<receiver>CrashReporter</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>424</x>
<y>154</y>
</hint>
<hint type="destinationlabel">
<x>247</x>
<y>195</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,56 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CrashReporter.h"
#include <QTranslator>
#include <iostream>
const char* k_usage =
"Usage:\n"
" CrashReporter <logDir> <dumpFileName> <productName>\n";
int main( int argc, char* argv[] )
{
// used by some Qt stuff, eg QSettings
// leave first! As Settings object is created quickly
QCoreApplication::setApplicationName( "Tomahawk" );
QCoreApplication::setOrganizationName( "Tomahawk" );
QCoreApplication::setOrganizationDomain( "tomahawk-player.org" );
QApplication app( argc, argv );
QString langCode;
QTranslator translatorApp;
QTranslator translatorQt;
/* app.installTranslator( &translatorApp );
app.installTranslator( &translatorQt );*/
if ( app.arguments().size() != 4 )
{
std::cout << k_usage;
return 1;
}
CrashReporter reporter( app.arguments() );
reporter.show();
return app.exec();
}

View File

@@ -642,4 +642,12 @@ createAvatarFrame( const QPixmap &avatar )
return frame;
}
void
crash()
{
volatile int* a = (int*)(NULL);
*a = 1;
}
} // ns

View File

@@ -99,6 +99,8 @@ namespace TomahawkUtils
DLLEXPORT void bringToFront();
DLLEXPORT QPixmap createAvatarFrame( const QPixmap &avatar );
DLLEXPORT void crash();
}
#endif // TOMAHAWKUTILS_H

View File

@@ -19,9 +19,12 @@
#include "tomahawkapp.h"
#include "thirdparty/kdsingleapplicationguard/kdsingleapplicationguard.h"
#include <QTranslator>
#ifdef Q_OS_LINUX
#include "breakpad/BreakPad.h"
#endif
#ifdef Q_WS_MAC
#include "tomahawkapp_mac.h"
#include </System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/AE.framework/Versions/A/Headers/AppleEvents.h>
@@ -32,6 +35,10 @@
int
main( int argc, char *argv[] )
{
#ifdef Q_OS_LINUX
new BreakPad( "/tmp" );
#endif
#ifdef Q_WS_MAC
// Do Mac specific startup to get media keys working.
// This must go before QApplication initialisation.

View File

@@ -100,6 +100,12 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
loadSettings();
setupSignals();
if ( qApp->arguments().contains( "--debug" ) )
{
ui->menu_Help->addSeparator();
ui->menu_Help->addAction( "Crash now...", this, SLOT( crashNow() ) );
}
// set initial state
onSipDisconnected();
vm->setQueue( m_queueView );
@@ -732,3 +738,10 @@ TomahawkWindow::maximize()
showMaximized();
}
}
void
TomahawkWindow::crashNow()
{
TomahawkUtils::crash();
}

View File

@@ -106,6 +106,8 @@ private slots:
void playlistCreateDialogFinished( int ret );
void crashNow();
private:
void loadSettings();
void saveSettings();