diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ActivityFramesTracker.java b/sentry-android-core/src/main/java/io/sentry/android/core/ActivityFramesTracker.java index 4dd16e03e00..80374b839a4 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ActivityFramesTracker.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ActivityFramesTracker.java @@ -5,7 +5,7 @@ import androidx.core.app.FrameMetricsAggregator; import io.sentry.MeasurementUnit; import io.sentry.SentryLevel; -import io.sentry.android.core.internal.util.MainThreadChecker; +import io.sentry.android.core.internal.util.AndroidMainThreadChecker; import io.sentry.protocol.MeasurementValue; import io.sentry.protocol.SentryId; import java.util.HashMap; @@ -208,7 +208,7 @@ public synchronized void stop() { private void runSafelyOnUiThread(final Runnable runnable, final String tag) { try { - if (MainThreadChecker.isMainThread()) { + if (AndroidMainThreadChecker.getInstance().isMainThread()) { runnable.run(); } else { handler.post( diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java index 821f1471195..5429b6e6250 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java @@ -13,6 +13,7 @@ import io.sentry.SentryLevel; import io.sentry.android.core.cache.AndroidEnvelopeCache; import io.sentry.android.core.internal.modules.AssetsModulesLoader; +import io.sentry.android.core.internal.util.AndroidMainThreadChecker; import io.sentry.android.core.internal.util.SentryFrameMetricsCollector; import io.sentry.android.fragment.FragmentLifecycleIntegration; import io.sentry.android.timber.SentryTimberIntegration; @@ -130,6 +131,7 @@ static void initializeIntegrationsAndProcessors( options.setTransactionProfiler( new AndroidTransactionProfiler(context, options, buildInfoProvider, frameMetricsCollector)); options.setModulesLoader(new AssetsModulesLoader(context, options.getLogger())); + options.setMainThreadChecker(AndroidMainThreadChecker.getInstance()); } private static void installDefaultIntegrations( diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AppLifecycleIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/AppLifecycleIntegration.java index fc9b48377f3..28aad388f48 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AppLifecycleIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AppLifecycleIntegration.java @@ -5,7 +5,7 @@ import io.sentry.Integration; import io.sentry.SentryLevel; import io.sentry.SentryOptions; -import io.sentry.android.core.internal.util.MainThreadChecker; +import io.sentry.android.core.internal.util.AndroidMainThreadChecker; import io.sentry.util.Objects; import java.io.Closeable; import java.io.IOException; @@ -56,7 +56,7 @@ public void register(final @NotNull IHub hub, final @NotNull SentryOptions optio try { Class.forName("androidx.lifecycle.DefaultLifecycleObserver"); Class.forName("androidx.lifecycle.ProcessLifecycleOwner"); - if (MainThreadChecker.isMainThread()) { + if (AndroidMainThreadChecker.getInstance().isMainThread()) { addObserver(hub); } else { // some versions of the androidx lifecycle-process require this to be executed on the main @@ -115,7 +115,7 @@ private void removeObserver() { @Override public void close() throws IOException { if (watcher != null) { - if (MainThreadChecker.isMainThread()) { + if (AndroidMainThreadChecker.getInstance().isMainThread()) { removeObserver(); } else { // some versions of the androidx lifecycle-process require this to be executed on the main diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java index bf17d90aab6..5fcccb36428 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java @@ -26,9 +26,9 @@ import io.sentry.SentryBaseEvent; import io.sentry.SentryEvent; import io.sentry.SentryLevel; +import io.sentry.android.core.internal.util.AndroidMainThreadChecker; import io.sentry.android.core.internal.util.ConnectivityChecker; import io.sentry.android.core.internal.util.DeviceOrientations; -import io.sentry.android.core.internal.util.MainThreadChecker; import io.sentry.android.core.internal.util.RootChecker; import io.sentry.protocol.App; import io.sentry.protocol.Device; @@ -217,7 +217,7 @@ private void setThreads(final @NotNull SentryEvent event) { if (event.getThreads() != null) { for (SentryThread thread : event.getThreads()) { if (thread.isCurrent() == null) { - thread.setCurrent(MainThreadChecker.isMainThread(thread)); + thread.setCurrent(AndroidMainThreadChecker.getInstance().isMainThread(thread)); } } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/AndroidMainThreadChecker.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/AndroidMainThreadChecker.java new file mode 100644 index 00000000000..a893fa87d16 --- /dev/null +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/AndroidMainThreadChecker.java @@ -0,0 +1,23 @@ +package io.sentry.android.core.internal.util; + +import android.os.Looper; +import io.sentry.util.thread.IMainThreadChecker; +import org.jetbrains.annotations.ApiStatus; + +/** Class that checks if a given thread is the Android Main/UI thread */ +@ApiStatus.Internal +public final class AndroidMainThreadChecker implements IMainThreadChecker { + + private static final AndroidMainThreadChecker instance = new AndroidMainThreadChecker(); + + public static AndroidMainThreadChecker getInstance() { + return instance; + } + + private AndroidMainThreadChecker() {} + + @Override + public boolean isMainThread(final long threadId) { + return Looper.getMainLooper().getThread().getId() == threadId; + } +} diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/MainThreadChecker.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/MainThreadChecker.java deleted file mode 100644 index c4c389134c3..00000000000 --- a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/MainThreadChecker.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.sentry.android.core.internal.util; - -import android.os.Looper; -import io.sentry.protocol.SentryThread; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -/** Class that checks if a given thread is the Android Main/UI thread */ -@ApiStatus.Internal -public final class MainThreadChecker { - - private MainThreadChecker() {} - - /** - * Checks if a given thread is the Android Main/UI thread - * - * @param thread the Thread - * @return true if it is the main thread or false otherwise - */ - public static boolean isMainThread(final @NotNull Thread thread) { - return isMainThread(thread.getId()); - } - - /** - * Checks if the calling/current thread is the Android Main/UI thread - * - * @return true if it is the main thread or false otherwise - */ - public static boolean isMainThread() { - return isMainThread(Thread.currentThread()); - } - - /** - * Checks if a given thread is the Android Main/UI thread - * - * @param sentryThread the SentryThread - * @return true if it is the main thread or false otherwise - */ - public static boolean isMainThread(final @NotNull SentryThread sentryThread) { - final Long threadId = sentryThread.getId(); - return threadId != null && isMainThread(threadId); - } - - private static boolean isMainThread(final long threadId) { - return Looper.getMainLooper().getThread().getId() == threadId; - } -} diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/MainThreadCheckerTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/AndroidMainThreadCheckerTest.kt similarity index 72% rename from sentry-android-core/src/test/java/io/sentry/android/core/internal/util/MainThreadCheckerTest.kt rename to sentry-android-core/src/test/java/io/sentry/android/core/internal/util/AndroidMainThreadCheckerTest.kt index 391074325ac..c759bdf79e0 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/MainThreadCheckerTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/AndroidMainThreadCheckerTest.kt @@ -8,23 +8,23 @@ import kotlin.test.assertFalse import kotlin.test.assertTrue @RunWith(AndroidJUnit4::class) -class MainThreadCheckerTest { +class AndroidMainThreadCheckerTest { @Test fun `When calling isMainThread from the same thread, it should return true`() { - assertTrue(MainThreadChecker.isMainThread()) + assertTrue(AndroidMainThreadChecker.getInstance().isMainThread) } @Test fun `When calling isMainThread with the current thread, it should return true`() { val thread = Thread.currentThread() - assertTrue(MainThreadChecker.isMainThread(thread)) + assertTrue(AndroidMainThreadChecker.getInstance().isMainThread(thread)) } @Test fun `When calling isMainThread from a different thread, it should return false`() { val thread = Thread() - assertFalse(MainThreadChecker.isMainThread(thread)) + assertFalse(AndroidMainThreadChecker.getInstance().isMainThread(thread)) } @Test @@ -33,7 +33,7 @@ class MainThreadCheckerTest { val sentryThread = SentryThread().apply { id = thread.id } - assertTrue(MainThreadChecker.isMainThread(sentryThread)) + assertTrue(AndroidMainThreadChecker.getInstance().isMainThread(sentryThread)) } @Test @@ -42,6 +42,6 @@ class MainThreadCheckerTest { val sentryThread = SentryThread().apply { id = thread.id } - assertFalse(MainThreadChecker.isMainThread(sentryThread)) + assertFalse(AndroidMainThreadChecker.getInstance().isMainThread(sentryThread)) } } diff --git a/sentry-samples/sentry-samples-android/proguard-rules.pro b/sentry-samples/sentry-samples-android/proguard-rules.pro index 95c4bb7bbca..1165340c893 100644 --- a/sentry-samples/sentry-samples-android/proguard-rules.pro +++ b/sentry-samples/sentry-samples-android/proguard-rules.pro @@ -16,7 +16,6 @@ # https://developer.android.com/studio/build/shrink-code#decode-stack-trace -keepattributes LineNumberTable,SourceFile - # For native methods, see http://proguard.sourceforge.net/manual/examples.html#native -keepclasseswithmembernames,includedescriptorclasses class * { native ; 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 6f3c4016339..72c6a4810fe 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 @@ -9,6 +9,7 @@ import io.sentry.Sentry; import io.sentry.SpanStatus; import io.sentry.UserFeedback; +import io.sentry.instrumentation.file.SentryFileOutputStream; import io.sentry.protocol.SentryId; import io.sentry.protocol.User; import io.sentry.samples.android.compose.ComposeActivity; @@ -79,7 +80,7 @@ protected void onCreate(Bundle savedInstanceState) { view -> { String fileName = Calendar.getInstance().getTimeInMillis() + "_file.txt"; File file = getApplication().getFileStreamPath(fileName); - try (final FileOutputStream fileOutputStream = new FileOutputStream(file); + try (final FileOutputStream fileOutputStream = new SentryFileOutputStream(file); final OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream); final Writer writer = new BufferedWriter(outputStreamWriter)) { diff --git a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/ThirdFragment.kt b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/ThirdFragment.kt index f9047f100b2..449b667fdac 100644 --- a/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/ThirdFragment.kt +++ b/sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/ThirdFragment.kt @@ -12,6 +12,9 @@ import retrofit2.Response class ThirdFragment : Fragment(R.layout.third_fragment) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + view.findViewById(R.id.third_button).setOnClickListener { + throw RuntimeException("Test") + } val span = Sentry.getSpan() val child = span?.startChild("calc") diff --git a/sentry-samples/sentry-samples-android/src/main/res/layout/third_fragment.xml b/sentry-samples/sentry-samples-android/src/main/res/layout/third_fragment.xml index c721c414425..98cd9b3921f 100644 --- a/sentry-samples/sentry-samples-android/src/main/res/layout/third_fragment.xml +++ b/sentry-samples/sentry-samples-android/src/main/res/layout/third_fragment.xml @@ -4,6 +4,7 @@ android:layout_width="match_parent" android:layout_height="match_parent">