From a26b64d684c030a70ea24e3e0e827265e2d39051 Mon Sep 17 00:00:00 2001 From: Sebastian Streich Date: Mon, 19 Sep 2022 17:44:53 +0200 Subject: [PATCH] Add Android support for sentry --- i18n | 2 +- scripts/android/package.sh | 8 +++++++ src/constants.h | 2 ++ src/networkrequest.cpp | 14 ++++++++++++ src/networkrequest.h | 3 +++ src/qmake/sentry.pri | 16 ++++++++++++++ src/qmake/sources.pri | 3 ++- src/sentry/sentryadapter.cpp | 37 ++++++++++++++++++++++++++++++++ src/sentry/sentryadapter.h | 2 +- src/src.pro | 1 + src/tasks/sentry/tasksentry.cpp | 38 +++++++++++++++++++++++++++++++++ src/tasks/sentry/tasksentry.h | 26 ++++++++++++++++++++++ 12 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 src/qmake/sentry.pri create mode 100644 src/tasks/sentry/tasksentry.cpp create mode 100644 src/tasks/sentry/tasksentry.h diff --git a/i18n b/i18n index ec729f908b..f686bdd0bc 160000 --- a/i18n +++ b/i18n @@ -1 +1 @@ -Subproject commit ec729f908b716ed456a6374797dbe54acbc8f82c +Subproject commit f686bdd0bc81e7e06a76f23853e03fe5dc69543a diff --git a/scripts/android/package.sh b/scripts/android/package.sh index b51dbe769f..a283e8aba4 100755 --- a/scripts/android/package.sh +++ b/scripts/android/package.sh @@ -127,6 +127,14 @@ rm -rf "android/src/com/adjust" || die "Failed to remove the adjust folder" cp -a "3rdparty/adjust-android-sdk/Adjust/sdk-core/src/main/java/com/." "android/src/com/" || die "Failed to copy the adjust codebase" git apply --directory="android/src/" "3rdparty/adjust_https_to_http.diff" || die "Failed to apply the adjust http patch" +print Y "Compile Sentry..." +cmake -B .tmp/sentry_build -S 3rdparty/sentry_native --toolchain ${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake \ + -DSENTRY_BUILD_SHARED_LIBS=false \ + -DANDROID_ABI=${ARCH} + +cmake --build .tmp/sentry_build --parallel +cmake --install .tmp/sentry_build --prefix .tmp/sentry_install --config RelWithDebInfo + printn Y "Computing the version... " export SHORTVERSION=$(cat version.pri | grep VERSION | grep defined | cut -d= -f2 | tr -d \ ) # Export so gradle can pick it up export VERSIONCODE=$(date +%s | sed 's/.\{3\}$//' )"0" #Remove the last 3 digits of the timestamp, so we only get every ~16m a new versioncode diff --git a/src/constants.h b/src/constants.h index 2c2ba08bbc..ca62bd4080 100644 --- a/src/constants.h +++ b/src/constants.h @@ -83,6 +83,8 @@ CONSTEXPR(uint32_t, controllerPeriodicStateRecorderMsec, 10800000, 60000, 0) constexpr const char* SENTRY_DER = "https://6a476c1b57a34773a75c60036236a01d@o1396220.ingest.sentry.io/" "6719480"; +constexpr const char* SENTRY_ENVELOPE_INGESTION = + "https://o1396220.ingest.sentry.io/api/6719480/envelope/"; constexpr const char* API_PRODUCTION_URL = "https://vpn.mozilla.org"; constexpr const char* API_STAGING_URL = diff --git a/src/networkrequest.cpp b/src/networkrequest.cpp index 3a1cbe735d..587220b197 100644 --- a/src/networkrequest.cpp +++ b/src/networkrequest.cpp @@ -693,6 +693,20 @@ NetworkRequest* NetworkRequest::createForFxaAuthz( return r; } +// static +NetworkRequest* NetworkRequest::createForSentry(Task* parent, + const QByteArray& envelope) { + NetworkRequest* r = new NetworkRequest(parent, 200, false); + QUrl url(Constants::SENTRY_ENVELOPE_INGESTION); + r->m_request.setUrl(url); + r->m_request.setHeader(QNetworkRequest::ContentTypeHeader, + "application/x-sentry-envelope"); + r->m_request.setRawHeader("dsn", Constants::SENTRY_DER); + r->postRequest(envelope); + + return r; +} + #ifdef UNIT_TEST // static NetworkRequest* NetworkRequest::createForFxaTotpCreation( diff --git a/src/networkrequest.h b/src/networkrequest.h index fb01ec4d31..2cade31eb4 100644 --- a/src/networkrequest.h +++ b/src/networkrequest.h @@ -115,6 +115,9 @@ class NetworkRequest final : public QObject { const QString& fxaScope, const QString& fxaAccessType); + static NetworkRequest* createForSentry(Task* parent, + const QByteArray& envelope); + #ifdef UNIT_TEST static NetworkRequest* createForFxaTotpCreation( Task* parent, const QByteArray& sessionToken); diff --git a/src/qmake/sentry.pri b/src/qmake/sentry.pri new file mode 100644 index 0000000000..2867314c5a --- /dev/null +++ b/src/qmake/sentry.pri @@ -0,0 +1,16 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +android{ + LIBS += $$PWD/../../.tmp/sentry_install/lib/libsentry.a + LIBS += $$PWD/../../.tmp/sentry_install/lib/libunwindstack.a + INCLUDEPATH += $$PWD/../../.tmp/sentry_install/include + SOURCES += sentry/sentryadapter.cpp + DEFINES += SENTRY_ENABLED + + # We need custom transport on android + DEFINES += SENTRY_TRANSPORT_ENABLED +}else{ + SOURCES += sentry/dummysentryadapter.cpp +} diff --git a/src/qmake/sources.pri b/src/qmake/sources.pri index 2d7dea2256..73c8a5cb60 100644 --- a/src/qmake/sources.pri +++ b/src/qmake/sources.pri @@ -129,7 +129,6 @@ SOURCES += \ rfc/rfc4193.cpp \ rfc/rfc4291.cpp \ rfc/rfc5735.cpp \ - sentry/dummysentryadapter.cpp \ serveri18n.cpp \ settingsholder.cpp \ signature.cpp \ @@ -154,6 +153,7 @@ SOURCES += \ tasks/release/taskrelease.cpp \ tasks/removedevice/taskremovedevice.cpp \ tasks/sendfeedback/tasksendfeedback.cpp \ + tasks/sentry/tasksentry.cpp \ tasks/servers/taskservers.cpp \ taskscheduler.cpp \ telemetry.cpp \ @@ -324,6 +324,7 @@ HEADERS += \ tasks/release/taskrelease.h \ tasks/removedevice/taskremovedevice.h \ tasks/sendfeedback/tasksendfeedback.h \ + tasks/sentry/tasksentry.h \ tasks/servers/taskservers.h \ taskscheduler.h \ telemetry.h \ diff --git a/src/sentry/sentryadapter.cpp b/src/sentry/sentryadapter.cpp index dc10b308df..502741067c 100644 --- a/src/sentry/sentryadapter.cpp +++ b/src/sentry/sentryadapter.cpp @@ -14,10 +14,13 @@ #include "logger.h" #include "settingsholder.h" #include "mozillavpn.h" +#include "tasks/sentry/tasksentry.h" +#include "taskscheduler.h" namespace { SentryAdapter* s_instance = nullptr; Logger logger(LOG_MAIN, "Sentry"); +void* transport_state = 0; } // namespace @@ -58,6 +61,13 @@ void SentryAdapter::init() { sentryFolder.toLocal8Bit().constData()); sentry_options_set_on_crash(options, &SentryAdapter::onCrash, NULL); +#ifdef SENTRY_TRANSPORT_ENABLED + sentry_transport_t* transport = + sentry_transport_new(&SentryAdapter::transportEnvelope); + sentry_transport_set_state(transport, transport_state); + sentry_options_set_transport(options, transport); +#endif + // Leaving this for convinence, be warned, it's spammy to stdout. // sentry_options_set_debug(options, 1); @@ -99,6 +109,8 @@ sentry_value_t SentryAdapter::onCrash( sentry_value_t event, // used the same way as in `before_send` void* closure // user-data that you can provide at configuration time ) { + Q_UNUSED(uctx); + Q_UNUSED(closure); logger.info() << "Sentry ON CRASH"; // Do contextual clean-up before the crash is sent to sentry's backend // infrastructure @@ -115,3 +127,28 @@ sentry_value_t SentryAdapter::onCrash( sentry_value_decref(event); return sentry_value_new_null(); } + +// static +void SentryAdapter::transportEnvelope(sentry_envelope_t* envelope, + void* state) { + /* + * Send the event here. If the transport requires state, such as an HTTP + * client object or request queue, it can be specified in the `state` + * parameter when configuring the transport. It will be passed as second + * argument to this function. + * The transport takes ownership of the `envelope`, and must free it once it + * is done. + */ + Q_UNUSED(state); + size_t sentry_buf_size = 0; + char* sentry_buf = sentry_envelope_serialize(envelope, &sentry_buf_size); + + // Qt Will copy this. + auto qt_owned_buffer = QByteArray(sentry_buf, sentry_buf_size); + // We can now free the stuff. + sentry_envelope_free(envelope); + sentry_free(sentry_buf); + + auto t = new TaskSentry(qt_owned_buffer); + TaskScheduler::scheduleTask(t); +} diff --git a/src/sentry/sentryadapter.h b/src/sentry/sentryadapter.h index 9ad7aeee26..e7cbd35061 100644 --- a/src/sentry/sentryadapter.h +++ b/src/sentry/sentryadapter.h @@ -37,7 +37,7 @@ class SentryAdapter final : public QObject { // Called before Sentry will send a crash report static sentry_value_t onCrash(const sentry_ucontext_t* uctx, sentry_value_t event, void* closure); - + static void transportEnvelope(sentry_envelope_t* envelope, void* state); #endif private: diff --git a/src/src.pro b/src/src.pro index 16e77e0a10..7a53df1cd8 100644 --- a/src/src.pro +++ b/src/src.pro @@ -14,6 +14,7 @@ include($$PWD/qmake/debug.pri) include($$PWD/qmake/includes_and_defines.pri) include($$PWD/qmake/qt.pri) include($$PWD/qmake/signature.pri) +include($$PWD/qmake/sentry.pri) include($$PWD/qmake/webextension.pri) include($$PWD/../glean/glean.pri) include($$PWD/../nebula/nebula.pri) diff --git a/src/tasks/sentry/tasksentry.cpp b/src/tasks/sentry/tasksentry.cpp new file mode 100644 index 0000000000..d570f9adf2 --- /dev/null +++ b/src/tasks/sentry/tasksentry.cpp @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "tasksentry.h" +#include "errorhandler.h" +#include "leakdetector.h" +#include "logger.h" +#include "mozillavpn.h" +#include "networkrequest.h" + +namespace { +Logger logger(LOG_MAIN, "TaskSentry"); +} + +TaskSentry::TaskSentry(const QByteArray& envelope) : Task("TaskSentry") { + MVPN_COUNT_CTOR(TaskSentry); + m_envelope = envelope; +} + +TaskSentry::~TaskSentry() { MVPN_COUNT_DTOR(TaskSentry); } + +void TaskSentry::run() { + NetworkRequest* request = NetworkRequest::createForSentry(this, m_envelope); + + connect(request, &NetworkRequest::requestFailed, this, + [this](QNetworkReply::NetworkError error, const QByteArray&) { + Q_UNUSED(error); + logger.error() << "Failed to send envelope"; + emit completed(); + }); + connect(request, &NetworkRequest::requestCompleted, this, + [this](const QByteArray& data) { + Q_UNUSED(data); + logger.debug() << "Sentry sent events"; + emit completed(); + }); +} diff --git a/src/tasks/sentry/tasksentry.h b/src/tasks/sentry/tasksentry.h new file mode 100644 index 0000000000..19f7b2ca56 --- /dev/null +++ b/src/tasks/sentry/tasksentry.h @@ -0,0 +1,26 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef TASKSENTRY_H +#define TASKSENTRY_H + +#include "task.h" + +#include +#include + +class TaskSentry final : public Task { + Q_DISABLE_COPY_MOVE(TaskSentry) + + public: + TaskSentry(const QByteArray& envelope); + ~TaskSentry(); + + void run() override; + + private: + QByteArray m_envelope; +}; + +#endif // TASKSENTRY_H