diff --git a/backtrace-library/src/main/cpp/backends/crashpad-backend.cpp b/backtrace-library/src/main/cpp/backends/crashpad-backend.cpp index 1b49f087..6fb948fd 100644 --- a/backtrace-library/src/main/cpp/backends/crashpad-backend.cpp +++ b/backtrace-library/src/main/cpp/backends/crashpad-backend.cpp @@ -2,8 +2,11 @@ #include "handler/handler_main.h" #include "handler/crash_report_upload_thread.h" #include "backtrace-native.h" +#include "client/annotation.h" #include #include +#include +#include extern std::string thread_id; extern std::atomic_bool initialized; @@ -56,6 +59,50 @@ namespace { "Started Crashpad upload thread for offline native reports"); } + // Stores each attribute as a crashpad StringAnnotation in the global + // AnnotationList (unbounded), replacing the legacy simple_annotations + // dictionary that was limited to 64 entries. Once set, an annotation is + // permanently referenced by crashpad's global list, so annotations and + // their name buffers are allocated once and never freed. + constexpr crashpad::Annotation::ValueSizeType kAnnotationValueMaxSize = 4096; + using DynamicAnnotation = crashpad::StringAnnotation; + + std::unordered_map g_annotations; + + // Caller must hold attribute_synchronization. + DynamicAnnotation* GetOrCreateAnnotation(const std::string& key) { + auto it = g_annotations.find(key); + if (it != g_annotations.end()) { + return it->second; + } + char* nameCopy = new char[key.size() + 1]; + std::memcpy(nameCopy, key.c_str(), key.size() + 1); + DynamicAnnotation* annotation = new DynamicAnnotation(nameCopy); + g_annotations.emplace(key, annotation); + return annotation; + } + + void SetAnnotation(const char* rawKey, const char* rawValue) { + if (rawKey == nullptr || rawKey[0] == '\0') { + return; + } + const std::lock_guard lock(attribute_synchronization); + DynamicAnnotation* annotation = GetOrCreateAnnotation(std::string(rawKey)); + // Set(const char*) uses strncpy; the StringPiece overload uses std::copy. + annotation->Set(base::StringPiece(rawValue != nullptr ? rawValue : "")); + } + + void ClearAnnotation(const char* rawKey) { + if (rawKey == nullptr || rawKey[0] == '\0') { + return; + } + const std::lock_guard lock(attribute_synchronization); + auto it = g_annotations.find(std::string(rawKey)); + if (it != g_annotations.end()) { + it->second->Clear(); + } + } + } // namespace std::vector @@ -325,23 +372,14 @@ void DumpWithoutCrashCrashpad(jstring message, jboolean set_main_thread_as_fault crashpad::CaptureContext(&context); // set dump message for single report - crashpad::SimpleStringDictionary *annotations = NULL; - if (message != NULL || set_main_thread_as_faulting_thread == true) { JNIEnv *env = GetJniEnv(); if (env == nullptr) { __android_log_print(ANDROID_LOG_ERROR, "Backtrace-Android", "Cannot initialize JNIEnv"); return; } - const std::lock_guard lock(attribute_synchronization); - crashpad::CrashpadInfo *info = crashpad::CrashpadInfo::GetCrashpadInfo(); - annotations = info->simple_annotations(); - if (!annotations) { - annotations = new crashpad::SimpleStringDictionary(); - info->set_simple_annotations(annotations); - } if (set_main_thread_as_faulting_thread == true) { - annotations->SetKeyValue("_mod_faulting_tid", thread_id); + SetAnnotation("_mod_faulting_tid", thread_id.c_str()); } if (message != NULL) { // user can't override error.message - exception message that Crashpad/crash-reporting tool @@ -349,14 +387,14 @@ void DumpWithoutCrashCrashpad(jstring message, jboolean set_main_thread_as_fault // report and after creating a dump, method will clean up this attribute. jboolean isCopy; const char *rawMessage = env->GetStringUTFChars(message, &isCopy); - annotations->SetKeyValue("error.message", rawMessage); + SetAnnotation("error.message", rawMessage); env->ReleaseStringUTFChars(message, rawMessage); } } client->DumpWithoutCrash(&context); - if (annotations != NULL) { - annotations->RemoveKey("error.message"); + if (message != NULL) { + ClearAnnotation("error.message"); } } @@ -372,22 +410,13 @@ void AddAttributeCrashpad(jstring key, jstring value) { return; } - const std::lock_guard lock(attribute_synchronization); - crashpad::CrashpadInfo *info = crashpad::CrashpadInfo::GetCrashpadInfo(); - crashpad::SimpleStringDictionary *annotations = info->simple_annotations(); - if (!annotations) { - annotations = new crashpad::SimpleStringDictionary(); - info->set_simple_annotations(annotations); - } - jboolean isCopy; const char *crashpadKey = env->GetStringUTFChars(key, &isCopy); const char *crashpadValue = env->GetStringUTFChars(value, &isCopy); - if (crashpadKey && crashpadValue) - annotations->SetKeyValue(crashpadKey, crashpadValue); + SetAnnotation(crashpadKey, crashpadValue); - env->ReleaseStringUTFChars(key, crashpadKey); - env->ReleaseStringUTFChars(value, crashpadValue); + if (crashpadKey) env->ReleaseStringUTFChars(key, crashpadKey); + if (crashpadValue) env->ReleaseStringUTFChars(value, crashpadValue); } void AddAttachmentCrashpad(jstring jattachment) {