From 14c4f0cd833b01c0b3bb72f2dcd7c576bdf79755 Mon Sep 17 00:00:00 2001 From: Lauri Alanko Date: Fri, 17 Jan 2025 21:22:51 +0200 Subject: [PATCH 01/11] Add native ANR button to sentry-samples-android Add a button to trigger ANR by holding a lock too long in native code. This can be used to test native stack frames in ANR events. --- .../src/main/cpp/native-sample.cpp | 25 +++++++++++++++++++ .../sentry/samples/android/MainActivity.java | 25 +++++++++++++++++++ .../sentry/samples/android/NativeSample.java | 3 +++ .../src/main/res/layout/activity_main.xml | 6 +++++ .../src/main/res/values/strings.xml | 1 + 5 files changed, 60 insertions(+) diff --git a/sentry-samples/sentry-samples-android/src/main/cpp/native-sample.cpp b/sentry-samples/sentry-samples-android/src/main/cpp/native-sample.cpp index 2a31e6c6e50..de1f0f0d3e1 100644 --- a/sentry-samples/sentry-samples-android/src/main/cpp/native-sample.cpp +++ b/sentry-samples/sentry-samples-android/src/main/cpp/native-sample.cpp @@ -22,4 +22,29 @@ JNIEXPORT void JNICALL Java_io_sentry_samples_android_NativeSample_message(JNIEn sentry_capture_event(event); } +[[gnu::noinline]] +static void idle_pointlessly() { + static const volatile int x = 42; + (void)x; +} + +[[gnu::noinline]] +static void loop_eternally() { + while (true) { + idle_pointlessly(); + } +} + +[[gnu::noinline]] +static void keep_object_locked(JNIEnv* env, jobject obj) { + env->MonitorEnter(obj); + loop_eternally(); + env->MonitorExit(obj); +} + +JNIEXPORT void JNICALL Java_io_sentry_samples_android_NativeSample_freezeMysteriously(JNIEnv *env, jclass cls, jobject obj) { + __android_log_print(ANDROID_LOG_WARN, TAG, "About to lock object eternally."); + keep_object_locked(env, obj); +} + } diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/MainActivity.java b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/MainActivity.java index da52c72a68d..e881612bd80 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/MainActivity.java +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/MainActivity.java @@ -210,6 +210,31 @@ public void run() { 1000); }); + binding.nativeAnr.setOnClickListener( + view -> { + new Thread( + new Runnable() { + @Override + public void run() { + NativeSample.freezeMysteriously(mutex); + } + }) + .start(); + + new Handler() + .postDelayed( + new Runnable() { + @Override + public void run() { + synchronized (mutex) { + // Shouldn't happen + throw new IllegalStateException(); + } + } + }, + 1000); + }); + binding.openSecondActivity.setOnClickListener( view -> { // finishing so its completely destroyed diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/NativeSample.java b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/NativeSample.java index bde645c6e31..064818ad4e0 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/NativeSample.java +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/NativeSample.java @@ -5,6 +5,9 @@ public class NativeSample { public static native void message(); + // Named to demonstrate the value of native stack frames during ANR + public static native void freezeMysteriously(Object obj); + static { System.loadLibrary("native-sample"); } diff --git a/sentry-samples/sentry-samples-android/src/main/res/layout/activity_main.xml b/sentry-samples/sentry-samples-android/src/main/res/layout/activity_main.xml index 6fb8d028637..b8a47c6bd59 100644 --- a/sentry-samples/sentry-samples-android/src/main/res/layout/activity_main.xml +++ b/sentry-samples/sentry-samples-android/src/main/res/layout/activity_main.xml @@ -64,6 +64,12 @@ android:layout_height="wrap_content" android:text="@string/anr" /> +