diff --git a/CHANGELOG.md b/CHANGELOG.md index f140ed0104..f6856071c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## TBD + +### Enhancements + +* Native crashes will now identify the crashing/error reporting thread + [#2087](https://github.com/bugsnag/bugsnag-android/pull/2087) + ## 6.8.0 (2024-09-30) ### Enhancements diff --git a/bugsnag-plugin-android-ndk/src/main/jni/event.h b/bugsnag-plugin-android-ndk/src/main/jni/event.h index d92324f394..4a63c721dc 100644 --- a/bugsnag-plugin-android-ndk/src/main/jni/event.h +++ b/bugsnag-plugin-android-ndk/src/main/jni/event.h @@ -191,6 +191,7 @@ typedef struct { typedef struct { pid_t id; + bool is_reporting_thread; char name[16]; char state[13]; } bsg_thread; diff --git a/bugsnag-plugin-android-ndk/src/main/jni/handlers/cpp_handler.cpp b/bugsnag-plugin-android-ndk/src/main/jni/handlers/cpp_handler.cpp index af8d7bf0f3..c02e8371bf 100644 --- a/bugsnag-plugin-android-ndk/src/main/jni/handlers/cpp_handler.cpp +++ b/bugsnag-plugin-android-ndk/src/main/jni/handlers/cpp_handler.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "../utils/crash_info.h" #include "../utils/serializer.h" @@ -58,7 +59,7 @@ void bsg_handle_cpp_terminate() { if (bsg_global_env->send_threads != SEND_THREADS_NEVER) { bsg_global_env->next_event.thread_count = bsg_capture_thread_states( - bsg_global_env->next_event.threads, BUGSNAG_THREADS_MAX); + gettid(), bsg_global_env->next_event.threads, BUGSNAG_THREADS_MAX); } else { bsg_global_env->next_event.thread_count = 0; } diff --git a/bugsnag-plugin-android-ndk/src/main/jni/handlers/signal_handler.c b/bugsnag-plugin-android-ndk/src/main/jni/handlers/signal_handler.c index 15afe15f70..613f747af8 100644 --- a/bugsnag-plugin-android-ndk/src/main/jni/handlers/signal_handler.c +++ b/bugsnag-plugin-android-ndk/src/main/jni/handlers/signal_handler.c @@ -188,7 +188,7 @@ void bsg_handle_signal(int signum, siginfo_t *info, if (bsg_global_env->send_threads != SEND_THREADS_NEVER) { bsg_global_env->next_event.thread_count = bsg_capture_thread_states( - bsg_global_env->next_event.threads, BUGSNAG_THREADS_MAX); + gettid(), bsg_global_env->next_event.threads, BUGSNAG_THREADS_MAX); } else { bsg_global_env->next_event.thread_count = 0; } diff --git a/bugsnag-plugin-android-ndk/src/main/jni/utils/serializer/event_writer.c b/bugsnag-plugin-android-ndk/src/main/jni/utils/serializer/event_writer.c index 935890205d..4b687eb7c8 100644 --- a/bugsnag-plugin-android-ndk/src/main/jni/utils/serializer/event_writer.c +++ b/bugsnag-plugin-android-ndk/src/main/jni/utils/serializer/event_writer.c @@ -605,6 +605,12 @@ static bool bsg_write_threads(BSG_KSJSONEncodeContext *json, CHECKED(bsg_ksjsonbeginObject(json, NULL)); { CHECKED(JSON_LIMITED_STRING_ELEMENT("id", id_string)); + + if (thread->is_reporting_thread) { + CHECKED( + bsg_ksjsonaddBooleanElement(json, "errorReportingThread", true)); + } + CHECKED(JSON_LIMITED_STRING_ELEMENT("name", thread->name)); CHECKED(JSON_LIMITED_STRING_ELEMENT("state", thread->state)); CHECKED(JSON_CONSTANT_ELEMENT("type", "c")); diff --git a/bugsnag-plugin-android-ndk/src/main/jni/utils/threads.c b/bugsnag-plugin-android-ndk/src/main/jni/utils/threads.c index 289477fddc..e641230208 100644 --- a/bugsnag-plugin-android-ndk/src/main/jni/utils/threads.c +++ b/bugsnag-plugin-android-ndk/src/main/jni/utils/threads.c @@ -167,7 +167,8 @@ static bool read_thread_state(bsg_thread *dest, const char *tid) { return parse_success; } -size_t bsg_capture_thread_states(bsg_thread *threads, size_t max_threads) { +size_t bsg_capture_thread_states(pid_t reporting_tid, bsg_thread *threads, + size_t max_threads) { size_t total_thread_count = 0; struct dirent64 *entry; char buffer[1024]; @@ -187,6 +188,8 @@ size_t bsg_capture_thread_states(bsg_thread *threads, size_t max_threads) { for (offset = 0; offset < available && total_thread_count < max_threads;) { entry = (struct dirent64 *)(buffer + offset); if (read_thread_state(&threads[total_thread_count], entry->d_name)) { + threads[total_thread_count].is_reporting_thread = + threads[total_thread_count].id == reporting_tid; total_thread_count += 1; } diff --git a/bugsnag-plugin-android-ndk/src/main/jni/utils/threads.h b/bugsnag-plugin-android-ndk/src/main/jni/utils/threads.h index b3943adcd6..df386dd6fc 100644 --- a/bugsnag-plugin-android-ndk/src/main/jni/utils/threads.h +++ b/bugsnag-plugin-android-ndk/src/main/jni/utils/threads.h @@ -10,7 +10,7 @@ extern "C" { #define MAX_STAT_PATH_LENGTH 64 -size_t bsg_capture_thread_states(bsg_thread *threads, +size_t bsg_capture_thread_states(pid_t reporting_tid, bsg_thread *threads, size_t max_threads) __asyncsafe; #ifdef __cplusplus diff --git a/features/smoke_tests/04_unhandled.feature b/features/smoke_tests/04_unhandled.feature index 6eb54cffb8..73158a07c4 100644 --- a/features/smoke_tests/04_unhandled.feature +++ b/features/smoke_tests/04_unhandled.feature @@ -292,3 +292,9 @@ Feature: Unhandled smoke tests # Breadcrumbs And the event has a "manual" breadcrumb named "CXXExceptionSmokeScenario" + # Threads validation + And the error payload field "events.0.threads" is a non-empty array + And the event "threads.0.id" matches "^[0-9]+$" + And the event "threads.0.name" is not null + And the event "threads.0.type" equals "c" + And the thread with name "roid.mazerunner" contains the error reporting flag \ No newline at end of file