From abee1baf41a32bac56fdb3e8e70381959e01423c Mon Sep 17 00:00:00 2001 From: George Menhorn Date: Fri, 27 Mar 2026 16:54:31 -0400 Subject: [PATCH] backtrace-android: add support for dynamic attachments with native crashes Previously, crashpad, used for handling native crashes, did not support additional file attachments to the crash report context after initialization. Recent changes, however, have been made to the Backtrace fork of crashpad to allow this. The crashpad submodule reference has been updated in this commit to point to this change. This commit adds support for adding file attachments after initialization to native crash reports. The changes follow the existing pattern for adding attributes dynamically which forward the request to the crashpad backend in response to a call to `addAttachment` on the Backtrace client. --- .../src/main/cpp/backends/backend.cpp | 11 ++++++++- .../main/cpp/backends/crashpad-backend.cpp | 23 +++++++++++++++++++ .../src/main/cpp/backtrace-native.cpp | 8 ++++++- backtrace-library/src/main/cpp/crashpad | 2 +- .../src/main/cpp/include/backend.h | 1 + .../src/main/cpp/include/crashpad-backend.h | 1 + .../library/BacktraceDatabase.java | 15 ++++++++++++ .../library/base/BacktraceBase.java | 16 ++++--------- .../library/interfaces/Database.java | 8 +++++++ 9 files changed, 70 insertions(+), 15 deletions(-) diff --git a/backtrace-library/src/main/cpp/backends/backend.cpp b/backtrace-library/src/main/cpp/backends/backend.cpp index 1948b1fa1..a75811b05 100644 --- a/backtrace-library/src/main/cpp/backends/backend.cpp +++ b/backtrace-library/src/main/cpp/backends/backend.cpp @@ -108,6 +108,15 @@ void AddAttribute(jstring key, jstring value) { #endif } +void AddAttachment(jstring attachment) { +#ifdef CRASHPAD_BACKEND + AddAttachmentCrashpad(attachment); +#else + __android_log_print(ANDROID_LOG_ERROR, "Backtrace-Android", + "AddAttachment not supported on this backend"); +#endif +} + void Disable() { #ifdef CRASHPAD_BACKEND DisableCrashpad(); @@ -116,4 +125,4 @@ void Disable() { "Disable not supported on this backend"); #endif } -} \ No newline at end of file +} diff --git a/backtrace-library/src/main/cpp/backends/crashpad-backend.cpp b/backtrace-library/src/main/cpp/backends/crashpad-backend.cpp index 11c4e3c3c..1b49f087e 100644 --- a/backtrace-library/src/main/cpp/backends/crashpad-backend.cpp +++ b/backtrace-library/src/main/cpp/backends/crashpad-backend.cpp @@ -390,6 +390,29 @@ void AddAttributeCrashpad(jstring key, jstring value) { env->ReleaseStringUTFChars(value, crashpadValue); } +void AddAttachmentCrashpad(jstring jattachment) { + if (initialized == false || client == nullptr) { + __android_log_print(ANDROID_LOG_WARN, "Backtrace-Android", + "Crashpad integration isn't available. Please initialize the Crashpad integration first."); + return; + } + JNIEnv *env = GetJniEnv(); + if (env == nullptr) { + __android_log_print(ANDROID_LOG_ERROR, "Backtrace-Android", "Unable to obtain JNI environment."); + return; + } + + if (jattachment) { + jboolean isCopy; + const char *attachment = env->GetStringUTFChars(jattachment, &isCopy); + + if (attachment != nullptr) { + client->AddAttachment(attachment); + env->ReleaseStringUTFChars(jattachment, attachment); + } + } +} + void DisableCrashpad() { if (database == nullptr) { __android_log_print(ANDROID_LOG_ERROR, "Backtrace-Android", diff --git a/backtrace-library/src/main/cpp/backtrace-native.cpp b/backtrace-library/src/main/cpp/backtrace-native.cpp index 98d79f55d..92ba30441 100644 --- a/backtrace-library/src/main/cpp/backtrace-native.cpp +++ b/backtrace-library/src/main/cpp/backtrace-native.cpp @@ -161,6 +161,12 @@ Java_backtraceio_library_BacktraceDatabase_addAttribute(JNIEnv *env, jobject thi AddAttribute(name, value); } +JNIEXPORT void JNICALL +Java_backtraceio_library_BacktraceDatabase_addAttachment(JNIEnv *env, jobject thiz, + jstring jattachment) { + AddAttachment(jattachment); +} + JNIEXPORT void JNICALL Java_backtraceio_library_base_BacktraceBase_dumpWithoutCrash__Ljava_lang_String_2(JNIEnv *env, jobject thiz, @@ -186,4 +192,4 @@ Java_backtraceio_library_nativeCalls_BacktraceCrashHandler_handleCrash(JNIEnv *e jobjectArray args) { return CaptureCrash(args); } -} \ No newline at end of file +} diff --git a/backtrace-library/src/main/cpp/crashpad b/backtrace-library/src/main/cpp/crashpad index 9fd330062..5d89b9b3d 160000 --- a/backtrace-library/src/main/cpp/crashpad +++ b/backtrace-library/src/main/cpp/crashpad @@ -1 +1 @@ -Subproject commit 9fd3300629a59b5b19e58280c5067f1745f6beb2 +Subproject commit 5d89b9b3d4bfacb2fd25c591745afdd34997a2fb diff --git a/backtrace-library/src/main/cpp/include/backend.h b/backtrace-library/src/main/cpp/include/backend.h index 39b9e240a..7a18f80fe 100644 --- a/backtrace-library/src/main/cpp/include/backend.h +++ b/backtrace-library/src/main/cpp/include/backend.h @@ -27,6 +27,7 @@ bool CaptureCrash(jobjectArray args); void DumpWithoutCrash(jstring message, jboolean set_main_thread_as_faulting_thread); void AddAttribute(jstring key, jstring value); +void AddAttachment(jstring jattachment); void Disable(); } diff --git a/backtrace-library/src/main/cpp/include/crashpad-backend.h b/backtrace-library/src/main/cpp/include/crashpad-backend.h index d06eab9c7..33e8f9bea 100644 --- a/backtrace-library/src/main/cpp/include/crashpad-backend.h +++ b/backtrace-library/src/main/cpp/include/crashpad-backend.h @@ -33,6 +33,7 @@ bool CaptureCrashCrashpad(jobjectArray args); void DumpWithoutCrashCrashpad(jstring message, jboolean set_main_thread_as_faulting_thread); void AddAttributeCrashpad(jstring key, jstring value); +void AddAttachmentCrashpad(jstring jattachment); void DisableCrashpad(); diff --git a/backtrace-library/src/main/java/backtraceio/library/BacktraceDatabase.java b/backtrace-library/src/main/java/backtraceio/library/BacktraceDatabase.java index 365c6d7b9..a225861ea 100644 --- a/backtrace-library/src/main/java/backtraceio/library/BacktraceDatabase.java +++ b/backtrace-library/src/main/java/backtraceio/library/BacktraceDatabase.java @@ -64,6 +64,13 @@ public class BacktraceDatabase implements Database { */ public native void addAttribute(String name, String value); + /** + * Add a file attachment to native reports. + * + * @param attachmentPath the file path to attach to native reports + */ + public native void addAttachment(String attachmentPath); + /** * Disable Backtrace-native integration */ @@ -255,6 +262,14 @@ public Boolean addNativeAttribute(String key, Object value) { return true; } + public Boolean addNativeAttachment(String attachmentPath) { + if (!_enabledNativeIntegration || attachmentPath == null) { + return false; + } + addAttachment(attachmentPath); + return true; + } + public void start() { if (databaseSettings == null) { return; diff --git a/backtrace-library/src/main/java/backtraceio/library/base/BacktraceBase.java b/backtrace-library/src/main/java/backtraceio/library/base/BacktraceBase.java index 1c4aba5ab..2c69b7430 100644 --- a/backtrace-library/src/main/java/backtraceio/library/base/BacktraceBase.java +++ b/backtrace-library/src/main/java/backtraceio/library/base/BacktraceBase.java @@ -102,8 +102,6 @@ public BacktraceBase(Context context, BacktraceCredentials credentials) { * @param context context of current state of the application * @param credentials Backtrace credentials to access Backtrace API * @param attachments File attachment paths to consider for reports - * @note Attachments for native crashes must be specified here, and cannot be - * changed during runtime */ public BacktraceBase(Context context, BacktraceCredentials credentials, List attachments) { this(context, credentials, (Database) null, attachments); @@ -127,8 +125,6 @@ public BacktraceBase(Context context, BacktraceCredentials credentials, Map attachments) { @@ -251,8 +241,6 @@ public BacktraceBase( * @param database Backtrace database * @param attributes additional information about current application * @param attachments File attachment paths to consider for reports - * @note Attachments for native crashes must be specified here, and cannot be - * changed during runtime */ public BacktraceBase( Context context, @@ -336,6 +324,10 @@ public void enableProguard() { */ public void addAttachment(String attachmentPath) { this.attachments.add(attachmentPath); + + if (database != null) { + database.addNativeAttachment(attachmentPath); + } } /** diff --git a/backtrace-library/src/main/java/backtraceio/library/interfaces/Database.java b/backtrace-library/src/main/java/backtraceio/library/interfaces/Database.java index 05aaf0db6..5bc6fcd32 100644 --- a/backtrace-library/src/main/java/backtraceio/library/interfaces/Database.java +++ b/backtrace-library/src/main/java/backtraceio/library/interfaces/Database.java @@ -132,4 +132,12 @@ Boolean setupNativeIntegration( * @return true, if attribute was added to the native report. Otherwise false. */ Boolean addNativeAttribute(String key, Object value); + + /** + * If the native integration is enabled then adds a file attachment to be included + * with native crash reports. + * @param attachmentPath the file path to attach to native reports. + * @return whether the attachment was added to the native report or not. + */ + Boolean addNativeAttachment(String attachmentPath); }