diff --git a/CHANGELOG.md b/CHANGELOG.md index a3d0cec6fc1..3ba00f4a517 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -115,6 +115,7 @@ ### Internal - Measure the 30 second performance-collection budget on a monotonic ticker, so that a device time change no longer ends collection early or extends it past the budget ([#6101](https://github.com/getsentry/sentry-java/pull/6101)) +- Narrow `catch (Throwable)` to the exceptions the guarded code throws, so SDK bugs and fatal errors are no longer swallowed ([#6564](https://github.com/getsentry/sentry-java/pull/6564)) ## 8.63.0 diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidContinuousProfiler.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidContinuousProfiler.java index 23a72b131fc..7cedd3ad141 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidContinuousProfiler.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidContinuousProfiler.java @@ -383,7 +383,7 @@ private void sendChunks(final @NotNull IScopes scopes, final @NotNull SentryOpti scopes.captureProfileChunk(payload); } }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.DEBUG, "Failed to send profile chunks.", e); } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidLoggerBatchProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidLoggerBatchProcessor.java index b81666e2f38..6dd05c76de1 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidLoggerBatchProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidLoggerBatchProcessor.java @@ -4,6 +4,7 @@ import io.sentry.SentryLevel; import io.sentry.SentryOptions; import io.sentry.logger.LoggerBatchProcessor; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -37,7 +38,7 @@ public void run() { flush(LoggerBatchProcessor.FLUSH_AFTER_MS); } }); - } catch (Throwable t) { + } catch (RejectedExecutionException t) { options.getLogger().log(SentryLevel.ERROR, t, "Failed to submit log flush in onBackground()"); } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidMetricsBatchProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidMetricsBatchProcessor.java index d92c4369139..2cba40bb863 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidMetricsBatchProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidMetricsBatchProcessor.java @@ -4,6 +4,7 @@ import io.sentry.SentryLevel; import io.sentry.SentryOptions; import io.sentry.metrics.MetricsBatchProcessor; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -37,7 +38,7 @@ public void run() { flush(MetricsBatchProcessor.FLUSH_AFTER_MS); } }); - } catch (Throwable t) { + } catch (RejectedExecutionException t) { options .getLogger() .log(SentryLevel.ERROR, t, "Failed to submit metrics flush in onBackground()"); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidProfiler.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidProfiler.java index 8710c5d637f..e6b559a0d8c 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidProfiler.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidProfiler.java @@ -214,7 +214,7 @@ public void onFrameMetricCollected( isRunning = true; return new ProfileStartData( profileStartNanos, profileStartCpuMillis, profileStartTimestamp); - } catch (Throwable e) { + } catch (RuntimeException e) { endAndCollect(false, null); logger.log(SentryLevel.ERROR, "Unable to start a profile: ", e); isRunning = false; @@ -237,7 +237,7 @@ public void onFrameMetricCollected( // wrapped, so this should never happen (except for tests, where this is the only method // that throws) Debug.stopMethodTracing(); - } catch (Throwable e) { + } catch (RuntimeException e) { logger.log(SentryLevel.ERROR, "Error while stopping profiling: ", e); } finally { isRunning = false; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AnrIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/AnrIntegration.java index 275914e3fe2..389f050a044 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AnrIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AnrIntegration.java @@ -20,6 +20,7 @@ import io.sentry.util.Objects; import java.io.Closeable; import java.io.IOException; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -75,7 +76,7 @@ private void register( } } }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options .getLogger() .log(SentryLevel.DEBUG, "Failed to start AnrIntegration on executor thread.", e); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java b/sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java index c80ce982b95..88642d408c3 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java @@ -39,6 +39,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.List; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -87,7 +88,7 @@ public void register(@NotNull IScopes scopes, @NotNull SentryOptions options) { .submit( new ApplicationExitInfoHistoryDispatcher( context, scopes, this.options, dateProvider, new AnrV2Policy(this.options))); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.DEBUG, "Failed to start ANR processor.", e); } options.getLogger().log(SentryLevel.DEBUG, "AnrV2Integration installed."); @@ -203,7 +204,7 @@ public void markReported(final long timestamp) { return new ParseResult(ParseResult.Type.NO_DUMP); } dump = NativeEventUtils.readBytes(trace); - } catch (Throwable e) { + } catch (IOException e) { options.getLogger().log(SentryLevel.WARNING, "Failed to read ANR thread dump", e); return new ParseResult(ParseResult.Type.NO_DUMP); } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegration.java index e98c0afb2db..a2ca81faa9a 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AppComponentsBreadcrumbsIntegration.java @@ -20,6 +20,7 @@ import java.io.Closeable; import java.io.IOException; import java.util.Locale; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -173,7 +174,7 @@ private void executeInBackground(final @NotNull Runnable runnable) { if (options != null) { try { options.getExecutorService().submit(runnable); - } catch (Throwable t) { + } catch (RejectedExecutionException t) { options .getLogger() .log(SentryLevel.ERROR, t, "Failed to submit app components breadcrumb task"); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ApplicationExitInfoEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/ApplicationExitInfoEventProcessor.java index 79e671b4f49..2b624c8982a 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ApplicationExitInfoEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ApplicationExitInfoEventProcessor.java @@ -234,7 +234,7 @@ private boolean sampleReplay( event.getEventId()); return false; } - } catch (Throwable e) { + } catch (NumberFormatException e) { options.getLogger().log(SentryLevel.ERROR, "Error parsing replay sample rate.", e); return false; } @@ -467,7 +467,7 @@ private void setAppVersionAndBuild(final @NotNull SentryBaseEvent event) { app.setAppVersion(versionName); app.setAppBuild(versionCode); event.getContexts().setApp(app); - } catch (Throwable e) { + } catch (IndexOutOfBoundsException e) { options .getLogger() .log(SentryLevel.WARNING, "Failed to parse release from scope cache: %s", release); @@ -698,7 +698,7 @@ private void mergeUser(final @NotNull SentryBaseEvent event) { private @Nullable String getDeviceId() { try { return Installation.id(context); - } catch (Throwable e) { + } catch (RuntimeException e) { options.getLogger().log(SentryLevel.ERROR, "Error getting installationId.", e); } return null; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java b/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java index 3cc0b3c67f5..146566a754d 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java @@ -485,7 +485,7 @@ private Long getUnusedExternalStorage(final @NotNull StatFs stat) { private String getDeviceId() { try { return Installation.id(context); - } catch (Throwable e) { + } catch (RuntimeException e) { options.getLogger().log(SentryLevel.ERROR, "Error getting installationId.", e); } return null; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserverIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserverIntegration.java index ab95ae32daa..b5c254a88c1 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserverIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/EnvelopeFileObserverIntegration.java @@ -14,6 +14,7 @@ import io.sentry.util.Objects; import java.io.Closeable; import java.io.File; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -56,7 +57,7 @@ public final void register(final @NotNull IScopes scopes, final @NotNull SentryO } } }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { logger.log( SentryLevel.DEBUG, "Failed to start EnvelopeFileObserverIntegration on executor thread.", diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/FeedbackShakeIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/FeedbackShakeIntegration.java index 4405cd19309..b2a47afda2c 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/FeedbackShakeIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/FeedbackShakeIntegration.java @@ -16,6 +16,7 @@ import java.io.IOException; import java.lang.ref.WeakReference; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -97,7 +98,7 @@ public synchronized void enableOnShake() { options .getExecutorService() .submit(() -> shakeDetector.init(application, options.getLogger())); - } catch (Throwable t) { + } catch (RejectedExecutionException t) { options .getLogger() .log(SentryLevel.WARNING, "Failed to submit shake detector initialization.", t); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java b/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java index 4ad11399d02..fb4fef1383e 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java @@ -41,6 +41,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicReference; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -419,7 +420,7 @@ private static void deleteCurrentSessionFile( () -> { deleteCurrentSessionFile(options); }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options .getLogger() .log(WARNING, "Submission of deletion of the current session file rejected.", e); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/LifecycleWatcher.java b/sentry-android-core/src/main/java/io/sentry/android/core/LifecycleWatcher.java index f0078bc353e..98e66d247ce 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/LifecycleWatcher.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/LifecycleWatcher.java @@ -11,6 +11,7 @@ import io.sentry.util.AutoClosableReentrantLock; import java.util.Date; import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.jetbrains.annotations.NotNull; @@ -131,7 +132,7 @@ private void scheduleEndSession() { .getOptions() .getTimerExecutorService() .schedule(endSession, sessionEnd.remaining(TimeUnit.MILLISECONDS)); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { scopes .getOptions() .getLogger() diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/NativeEventCollector.java b/sentry-android-core/src/main/java/io/sentry/android/core/NativeEventCollector.java index 69dfa9c16be..df6d843cae2 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/NativeEventCollector.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/NativeEventCollector.java @@ -223,7 +223,7 @@ public boolean deleteNativeEventFile(final @NotNull NativeEventData nativeEventD file.getAbsolutePath()); return false; } - } catch (Throwable e) { + } catch (SecurityException e) { options .getLogger() .log( diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/PerfettoContinuousProfiler.java b/sentry-android-core/src/main/java/io/sentry/android/core/PerfettoContinuousProfiler.java index 15ae88f22c8..002ad4200de 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/PerfettoContinuousProfiler.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/PerfettoContinuousProfiler.java @@ -552,7 +552,7 @@ private void sendChunk( } else { executorServiceSupplier.evaluate().submit(task); } - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.DEBUG, "Failed to send profile chunk.", e); } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SendCachedEnvelopeIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/SendCachedEnvelopeIntegration.java index 8eea2d71047..22ff7dc92b9 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SendCachedEnvelopeIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SendCachedEnvelopeIntegration.java @@ -16,6 +16,7 @@ import io.sentry.util.Objects; import java.io.Closeable; import java.io.IOException; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; @@ -157,6 +158,14 @@ private void sendCachedEnvelopes( options .getLogger() .log(SentryLevel.DEBUG, "Synchronous send timed out, continuing in the background."); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + options + .getLogger() + .log( + SentryLevel.DEBUG, "Synchronous send interrupted, continuing in the background."); + } catch (ExecutionException e) { + options.getLogger().log(SentryLevel.ERROR, "Failed trying to send cached events.", e); } } options.getLogger().log(SentryLevel.DEBUG, "SendCachedEnvelopeIntegration installed."); @@ -167,10 +176,6 @@ private void sendCachedEnvelopes( SentryLevel.ERROR, "Failed to call the executor. Cached events will not be sent. Did you call Sentry.close()?", e); - } catch (Throwable e) { - options - .getLogger() - .log(SentryLevel.ERROR, "Failed to call the executor. Cached events will not be sent", e); } } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java index 3f45a9a9fb8..15ec2321be5 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/SystemEventsBreadcrumbsIntegration.java @@ -187,7 +187,7 @@ private void registerReceiver( } } }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options .getLogger() .log( diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/TombstoneIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/TombstoneIntegration.java index 43de4034ec5..215af07dad3 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/TombstoneIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/TombstoneIntegration.java @@ -44,6 +44,7 @@ import java.time.Instant; import java.time.format.DateTimeFormatter; import java.util.List; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -98,7 +99,7 @@ public void register(@NotNull IScopes scopes, @NotNull SentryOptions options) { this.options, dateProvider, new TombstonePolicy(this.options, this.context))); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.DEBUG, "Failed to start tombstone processor.", e); } options.getLogger().log(SentryLevel.DEBUG, "TombstoneIntegration installed."); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfileRotationHelper.java b/sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfileRotationHelper.java index 761309f1670..75b4b776dff 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfileRotationHelper.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfileRotationHelper.java @@ -37,13 +37,13 @@ private static void performRotationIfNeeded(final @NotNull File cacheDir) { try { oldFile.delete(); - } catch (Throwable e) { + } catch (SecurityException e) { // ignored } try { currentFile.renameTo(oldFile); - } catch (Throwable e) { + } catch (SecurityException e) { // ignored } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfilingIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfilingIntegration.java index 1a8552c51a8..80c25ec3305 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfilingIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfilingIntegration.java @@ -22,6 +22,7 @@ import java.io.Closeable; import java.io.File; import java.io.IOException; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -143,7 +144,7 @@ public void close() throws IOException { logger.log(SentryLevel.WARNING, "Failed to close AnrProfileManager"); } }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { logger.log(SentryLevel.WARNING, "Failed to submit AnrProfileManager close"); } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/cache/AndroidEnvelopeCache.java b/sentry-android-core/src/main/java/io/sentry/android/core/cache/AndroidEnvelopeCache.java index 13148097289..966ded83beb 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/cache/AndroidEnvelopeCache.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/cache/AndroidEnvelopeCache.java @@ -23,6 +23,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.IOException; import java.io.OutputStream; import java.util.Arrays; import java.util.List; @@ -120,7 +121,7 @@ private void writeStartupCrashMarkerFile() { final File crashMarkerFile = new File(outboxDir, STARTUP_CRASH_MARKER_FILE); try { crashMarkerFile.createNewFile(); - } catch (Throwable e) { + } catch (IOException e) { options.getLogger().log(ERROR, "Error writing the startup crash marker file to the disk", e); } } @@ -148,7 +149,7 @@ public static boolean hasStartupCrashMarker(final @NotNull SentryOptions options } } return exists; - } catch (Throwable e) { + } catch (SecurityException e) { options .getLogger() .log(ERROR, "Error reading/deleting the startup crash marker file on the disk", e); @@ -171,17 +172,15 @@ public static boolean hasStartupCrashMarker(final @NotNull SentryOptions options // we wrapped into try-catch already //noinspection ConstantConditions return (content == null || content.equals("null")) ? null : Long.parseLong(content.trim()); - } catch (Throwable e) { - if (e instanceof FileNotFoundException) { - options - .getLogger() - .log( - DEBUG, - "Last " + markerLabel + " marker does not exist. %s.", - lastMarker.getAbsolutePath()); - } else { - options.getLogger().log(ERROR, "Error reading last " + markerLabel + " marker", e); - } + } catch (FileNotFoundException e) { + options + .getLogger() + .log( + DEBUG, + "Last " + markerLabel + " marker does not exist. %s.", + lastMarker.getAbsolutePath()); + } catch (IOException | NumberFormatException e) { + options.getLogger().log(ERROR, "Error reading last " + markerLabel + " marker", e); } return null; } @@ -205,7 +204,7 @@ private static void writeLastReportedMarker( try (final OutputStream outputStream = new FileOutputStream(anrMarker)) { outputStream.write(String.valueOf(timestamp).getBytes(UTF_8)); outputStream.flush(); - } catch (Throwable e) { + } catch (IOException e) { options .getLogger() .log(ERROR, "Error writing the " + markerCategory + " marker to the disk", e); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/modules/AssetsModulesLoader.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/modules/AssetsModulesLoader.java index 1aa8a89f8fc..e8b0361c863 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/internal/modules/AssetsModulesLoader.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/modules/AssetsModulesLoader.java @@ -10,6 +10,7 @@ import java.io.InputStream; import java.util.Map; import java.util.TreeMap; +import java.util.concurrent.RejectedExecutionException; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -30,7 +31,7 @@ public AssetsModulesLoader(final @NotNull Context context, final @NotNull Sentry () -> { getOrLoadModules(); }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, "AssetsModulesLoader submit failed", e); } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/AndroidConnectionStatusProvider.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/AndroidConnectionStatusProvider.java index a5ff05e27d5..0b2f28a4cf5 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/AndroidConnectionStatusProvider.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/AndroidConnectionStatusProvider.java @@ -24,6 +24,7 @@ import io.sentry.util.AutoClosableReentrantLock; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.jetbrains.annotations.ApiStatus; @@ -788,7 +789,7 @@ public static List getChildCallbacks() { private void submitSafe(@NotNull Runnable r) { try { options.getExecutorService().submit(r); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options .getLogger() .log(SentryLevel.ERROR, "AndroidConnectionStatusProvider submit failed", e); diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/RootChecker.java b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/RootChecker.java index 2823f278a7d..8576469e719 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/RootChecker.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/internal/util/RootChecker.java @@ -169,7 +169,7 @@ private boolean checkRootC() { } } catch (IOException e) { logger.log(SentryLevel.DEBUG, "SU isn't found on this Device."); - } catch (Throwable e) { + } catch (SecurityException e) { logger.log(SentryLevel.DEBUG, "Error when trying to check if SU exists.", e); } finally { if (p != null) { diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidLoggerBatchProcessorTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidLoggerBatchProcessorTest.kt index d9f9b1e3edd..66ff1bd776f 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidLoggerBatchProcessorTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidLoggerBatchProcessorTest.kt @@ -10,6 +10,7 @@ import io.sentry.SentryOptions import io.sentry.protocol.SentryId import io.sentry.test.ImmediateExecutorService import io.sentry.test.getProperty +import java.util.concurrent.RejectedExecutionException import java.util.concurrent.atomic.AtomicBoolean import kotlin.test.AfterTest import kotlin.test.BeforeTest @@ -96,7 +97,7 @@ class AndroidLoggerBatchProcessorTest { fun `onBackground handles executor exception gracefully`() { val sut = fixture.getSut { options -> val rejectingExecutor = mock() - whenever(rejectingExecutor.submit(any())).thenThrow(RuntimeException("Rejected")) + whenever(rejectingExecutor.submit(any())).thenThrow(RejectedExecutionException("Rejected")) options.executorService = rejectingExecutor } sut.add(SentryLogEvent(SentryId(), 1.0, "test", SentryLogLevel.INFO)) diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidMetricsBatchProcessorTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidMetricsBatchProcessorTest.kt index 7648a2b3bab..9e7c20843c1 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/AndroidMetricsBatchProcessorTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/AndroidMetricsBatchProcessorTest.kt @@ -9,6 +9,7 @@ import io.sentry.SentryOptions import io.sentry.protocol.SentryId import io.sentry.test.ImmediateExecutorService import io.sentry.test.getProperty +import java.util.concurrent.RejectedExecutionException import java.util.concurrent.atomic.AtomicBoolean import kotlin.test.AfterTest import kotlin.test.BeforeTest @@ -95,7 +96,7 @@ class AndroidMetricsBatchProcessorTest { fun `onBackground handles executor exception gracefully`() { val sut = fixture.getSut { options -> val rejectingExecutor = mock() - whenever(rejectingExecutor.submit(any())).thenThrow(RuntimeException("Rejected")) + whenever(rejectingExecutor.submit(any())).thenThrow(RejectedExecutionException("Rejected")) options.executorService = rejectingExecutor } sut.add(SentryMetricsEvent(SentryId(), 1.0, "test", "counter", 3.0)) diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/ContextUtilsTestHelper.kt b/sentry-android-core/src/test/java/io/sentry/android/core/ContextUtilsTestHelper.kt index cd09d280d1a..89943fb2325 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/ContextUtilsTestHelper.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/ContextUtilsTestHelper.kt @@ -27,22 +27,31 @@ object ContextUtilsTestHelper { ) .thenReturn(mockApplicationInfo) - if (assets == null) { - val mockAssets = mock() - whenever(mockAssets.open(any())).thenThrow(FileNotFoundException()) - whenever(mockContext.assets).thenReturn(mockAssets) - } else { - whenever(mockContext.assets).thenReturn(assets) - } + val contextAssets = assets ?: assetsWithoutModulesFile() + whenever(mockContext.assets).thenReturn(contextAssets) mockApplicationInfo.metaData = metaData return mockContext } fun createMockContext(hasAppContext: Boolean = true): Context { + // A real Context always has assets. Without sentry-external-modules.txt, open() throws. + val assets = assetsWithoutModulesFile() val mockApp = mock() - whenever(mockApp.applicationContext) - .thenReturn(if (hasAppContext) mock() else null) + whenever(mockApp.assets).thenReturn(assets) + if (hasAppContext) { + val application = mock() + whenever(application.assets).thenReturn(assets) + whenever(mockApp.applicationContext).thenReturn(application) + } else { + whenever(mockApp.applicationContext).thenReturn(null) + } return mockApp } + + private fun assetsWithoutModulesFile(): AssetManager { + val mockAssets = mock() + whenever(mockAssets.open(any())).thenThrow(FileNotFoundException()) + return mockAssets + } } diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/RootCheckerTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/RootCheckerTest.kt index 71368b80ae9..bf99317f1fd 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/RootCheckerTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/internal/util/RootCheckerTest.kt @@ -14,6 +14,7 @@ import kotlin.test.Test import kotlin.test.assertFalse import kotlin.test.assertTrue import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.verify @@ -25,7 +26,10 @@ class RootCheckerTest { val logger = mock() val buildInfoProvider = mock() val packageManager = mock() - val runtime = mock() + // by default, `which su` finds nothing, like on a device without su + private val whichSuNotFound = + mock { on { inputStream } doReturn ByteArrayInputStream(ByteArray(0)) } + val runtime = mock { on { exec(any>()) } doReturn whichSuNotFound } fun getSut( tags: String? = "abc", diff --git a/sentry-android-ndk/src/main/java/io/sentry/android/ndk/NdkScopeObserver.java b/sentry-android-ndk/src/main/java/io/sentry/android/ndk/NdkScopeObserver.java index c35a294c828..f4e6bee54cb 100644 --- a/sentry-android-ndk/src/main/java/io/sentry/android/ndk/NdkScopeObserver.java +++ b/sentry-android-ndk/src/main/java/io/sentry/android/ndk/NdkScopeObserver.java @@ -49,7 +49,7 @@ public void setUser(final @Nullable User user) { user.getId(), user.getEmail(), user.getIpAddress(), user.getUsername()); } }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, e, "Scope sync setUser has an error."); } } @@ -96,7 +96,7 @@ public void addBreadcrumb(final @NotNull Breadcrumb crumb) { timestamp, data); }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, e, "Scope sync addBreadcrumb has an error."); } } @@ -105,7 +105,7 @@ public void addBreadcrumb(final @NotNull Breadcrumb crumb) { public void setTag(final @NotNull String key, final @NotNull String value) { try { options.getExecutorService().submit(() -> nativeScope.setTag(key, value)); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, e, "Scope sync setTag(%s) has an error.", key); } } @@ -114,7 +114,7 @@ public void setTag(final @NotNull String key, final @NotNull String value) { public void removeTag(final @NotNull String key) { try { options.getExecutorService().submit(() -> nativeScope.removeTag(key)); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, e, "Scope sync removeTag(%s) has an error.", key); } } @@ -123,7 +123,7 @@ public void removeTag(final @NotNull String key) { public void setExtra(final @NotNull String key, final @NotNull String value) { try { options.getExecutorService().submit(() -> nativeScope.setExtra(key, value)); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, e, "Scope sync setExtra(%s) has an error.", key); } } @@ -132,7 +132,7 @@ public void setExtra(final @NotNull String key, final @NotNull String value) { public void removeExtra(final @NotNull String key) { try { options.getExecutorService().submit(() -> nativeScope.removeExtra(key)); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options .getLogger() .log(SentryLevel.ERROR, e, "Scope sync removeExtra(%s) has an error.", key); @@ -152,7 +152,7 @@ public void setTrace(@Nullable SpanContext spanContext, @NotNull IScope scope) { () -> nativeScope.setTrace( spanContext.getTraceId().toString(), spanContext.getSpanId().toString())); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, e, "Scope sync setTrace failed."); } } @@ -163,7 +163,7 @@ public void addAttachment(final @NotNull Attachment attachment) { if (pathname != null) { try { options.getExecutorService().submit(() -> nativeScope.addAttachment(pathname)); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, e, "Scope sync addAttachment has an error."); } return; @@ -174,7 +174,7 @@ public void addAttachment(final @NotNull Attachment attachment) { final String filename = attachment.getFilename(); try { options.getExecutorService().submit(() -> nativeScope.addAttachmentBytes(bytes, filename)); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, e, "Scope sync addAttachment has an error."); } return; @@ -189,7 +189,7 @@ public void addAttachment(final @NotNull Attachment attachment) { public void clearAttachments() { try { options.getExecutorService().submit(() -> nativeScope.clearAttachments()); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.ERROR, e, "Scope sync clearAttachments has an error."); } } diff --git a/sentry-android-replay/src/main/java/io/sentry/android/replay/ReplayCache.kt b/sentry-android-replay/src/main/java/io/sentry/android/replay/ReplayCache.kt index 64aec8a077c..5d802388f6d 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/ReplayCache.kt +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/ReplayCache.kt @@ -246,7 +246,7 @@ public class ReplayCache(private val options: SentryOptions, private val replayI if (!file.delete()) { options.logger.log(ERROR, "Failed to delete replay frame: %s", file.absolutePath) } - } catch (e: Throwable) { + } catch (e: SecurityException) { options.logger.log(ERROR, e, "Failed to delete replay frame: %s", file.absolutePath) } } @@ -397,13 +397,13 @@ public class ReplayCache(private val options: SentryOptions, private val replayI val segmentTimestamp = try { DateUtils.getDateTime(lastSegment[SEGMENT_KEY_TIMESTAMP].orEmpty()) - } catch (e: Throwable) { + } catch (_: IllegalArgumentException) { null } val replayType = try { ReplayType.valueOf(lastSegment[SEGMENT_KEY_REPLAY_TYPE].orEmpty()) - } catch (e: Throwable) { + } catch (_: IllegalArgumentException) { null } if ( diff --git a/sentry-android-replay/src/main/java/io/sentry/android/replay/capture/BufferCaptureStrategy.kt b/sentry-android-replay/src/main/java/io/sentry/android/replay/capture/BufferCaptureStrategy.kt index 071acc19cae..37985e6cc80 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/capture/BufferCaptureStrategy.kt +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/capture/BufferCaptureStrategy.kt @@ -213,7 +213,7 @@ constructor( if (!file.delete()) { options.logger.log(ERROR, "Failed to delete replay segment: %s", file.absolutePath) } - } catch (e: Throwable) { + } catch (e: SecurityException) { options.logger.log(ERROR, e, "Failed to delete replay segment: %s", file.absolutePath) } } diff --git a/sentry-android-replay/src/main/java/io/sentry/android/replay/util/Executors.kt b/sentry-android-replay/src/main/java/io/sentry/android/replay/util/Executors.kt index a5dddc3bd4d..9b94d9198c4 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/util/Executors.kt +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/util/Executors.kt @@ -4,6 +4,7 @@ import io.sentry.ISentryExecutorService import io.sentry.SentryLevel.ERROR import io.sentry.SentryOptions import java.util.concurrent.Future +import java.util.concurrent.RejectedExecutionException internal fun ISentryExecutorService.submitSafely( options: SentryOptions, @@ -18,7 +19,7 @@ internal fun ISentryExecutorService.submitSafely( options.logger.log(ERROR, "Failed to execute task $taskName", e) } } - } catch (e: Throwable) { + } catch (e: RejectedExecutionException) { options.logger.log(ERROR, "Failed to submit task $taskName to executor", e) null } diff --git a/sentry-android-replay/src/main/java/io/sentry/android/replay/util/ReplayExecutorService.kt b/sentry-android-replay/src/main/java/io/sentry/android/replay/util/ReplayExecutorService.kt index 5ba334f8029..292d44b1e20 100644 --- a/sentry-android-replay/src/main/java/io/sentry/android/replay/util/ReplayExecutorService.kt +++ b/sentry-android-replay/src/main/java/io/sentry/android/replay/util/ReplayExecutorService.kt @@ -3,6 +3,7 @@ package io.sentry.android.replay.util import io.sentry.SentryLevel.ERROR import io.sentry.SentryOptions import java.util.concurrent.Future +import java.util.concurrent.RejectedExecutionException import java.util.concurrent.ScheduledExecutorService import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit.MILLISECONDS @@ -42,7 +43,7 @@ internal class ReplayExecutorService( ) } } - } catch (e: Throwable) { + } catch (e: RejectedExecutionException) { options.logger.log( ERROR, "Failed to submit task ${if (task is ReplayRunnable) task.taskName else ""} to executor", diff --git a/sentry-android-replay/src/test/java/io/sentry/android/replay/ReplayIntegrationTest.kt b/sentry-android-replay/src/test/java/io/sentry/android/replay/ReplayIntegrationTest.kt index 70e8426d124..a013ca6e2bc 100644 --- a/sentry-android-replay/src/test/java/io/sentry/android/replay/ReplayIntegrationTest.kt +++ b/sentry-android-replay/src/test/java/io/sentry/android/replay/ReplayIntegrationTest.kt @@ -105,7 +105,12 @@ class ReplayIntegrationTest { mock { on { breadcrumbConverter }.thenReturn(DefaultReplayBreadcrumbConverter()) } ) executorService = mock { - doAnswer { (it.arguments[0] as Runnable).run() }.whenever(mock).submit(any()) + doAnswer { + (it.arguments[0] as Runnable).run() + null + } + .whenever(mock) + .submit(any()) } } val scope = Scope(options) @@ -1272,7 +1277,10 @@ class ReplayIntegrationTest { // hold back the startup work, like a busy executor does val deferredTasks = mutableListOf() fixture.options.executorService = mock { - doAnswer { deferredTasks += it.arguments[0] as Runnable } + doAnswer { + deferredTasks += it.arguments[0] as Runnable + null + } .whenever(mock) .submit(any()) } @@ -1326,7 +1334,10 @@ class ReplayIntegrationTest { fixture.options.addScopeObserver(PersistingScopeObserver(fixture.options)) val deferredTasks = mutableListOf() fixture.options.executorService = mock { - doAnswer { deferredTasks += it.arguments[0] as Runnable } + doAnswer { + deferredTasks += it.arguments[0] as Runnable + null + } .whenever(mock) .submit(any()) } diff --git a/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt b/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt index 400643cef4a..2473266f2a5 100644 --- a/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt +++ b/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt @@ -39,6 +39,7 @@ import io.sentry.util.SpanUtils import io.sentry.util.TracingUtils import io.sentry.util.UrlUtils import io.sentry.vendor.Base64 +import java.io.IOException import kotlin.coroutines.cancellation.CancellationException import okio.Buffer import org.jetbrains.annotations.ApiStatus @@ -192,7 +193,7 @@ constructor( return getHeader(headerName, request.headers)?.let { try { String(Base64.decode(it, Base64.NO_WRAP)) - } catch (e: Throwable) { + } catch (e: IllegalArgumentException) { scopes.options.logger.log( SentryLevel.ERROR, "Error decoding internal apolloHeader $headerName", @@ -381,7 +382,7 @@ constructor( val body = try { response.body?.peek()?.readUtf8() ?: "" - } catch (e: Throwable) { + } catch (e: IOException) { scopes.options.logger.log(SentryLevel.ERROR, "Error reading the response body.", e) // bail out because the response body has the most important information return diff --git a/sentry-apollo-4/src/main/java/io/sentry/apollo4/SentryApollo4HttpInterceptor.kt b/sentry-apollo-4/src/main/java/io/sentry/apollo4/SentryApollo4HttpInterceptor.kt index 539bdb25b21..d2b7959cf48 100644 --- a/sentry-apollo-4/src/main/java/io/sentry/apollo4/SentryApollo4HttpInterceptor.kt +++ b/sentry-apollo-4/src/main/java/io/sentry/apollo4/SentryApollo4HttpInterceptor.kt @@ -37,6 +37,7 @@ import io.sentry.util.SpanUtils import io.sentry.util.TracingUtils import io.sentry.util.UrlUtils import io.sentry.vendor.Base64 +import java.io.IOException import java.util.Locale import kotlin.coroutines.cancellation.CancellationException import okio.Buffer @@ -191,7 +192,7 @@ constructor( return getHeader(headerName, request.headers)?.let { try { String(Base64.decode(it, Base64.NO_WRAP)) - } catch (e: Throwable) { + } catch (e: IllegalArgumentException) { scopes.options.logger.log( SentryLevel.ERROR, "Error decoding internal apolloHeader $headerName", @@ -380,7 +381,7 @@ constructor( val body = try { response.body?.peek()?.readUtf8() ?: "" - } catch (e: Throwable) { + } catch (e: IOException) { scopes.options.logger.log(SentryLevel.ERROR, "Error reading the response body.", e) // bail out because the response body has the most important information return diff --git a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/profiling/JavaContinuousProfiler.java b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/profiling/JavaContinuousProfiler.java index ced363d4a58..36ecf351818 100644 --- a/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/profiling/JavaContinuousProfiler.java +++ b/sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/profiling/JavaContinuousProfiler.java @@ -417,7 +417,7 @@ private void sendChunks(final @NotNull IScopes scopes, final @NotNull SentryOpti scopes.captureProfileChunk(payload); } }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.DEBUG, "Failed to send profile chunks.", e); } } diff --git a/sentry-jdbc/src/main/java/io/sentry/jdbc/DatabaseUtils.java b/sentry-jdbc/src/main/java/io/sentry/jdbc/DatabaseUtils.java index 4c442d4ae09..f45781c352d 100644 --- a/sentry-jdbc/src/main/java/io/sentry/jdbc/DatabaseUtils.java +++ b/sentry-jdbc/src/main/java/io/sentry/jdbc/DatabaseUtils.java @@ -4,6 +4,7 @@ import com.p6spy.engine.common.StatementInformation; import io.sentry.util.StringUtils; import java.net.URI; +import java.net.URISyntaxException; import java.util.Locale; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -46,7 +47,7 @@ public static DatabaseDetails parse(final @Nullable String databaseConnectionUrl final @NotNull String dbSystem = urlParts[0]; return parseDbSystemSpecific(dbSystem, urlParts, rawUrl); } - } catch (Throwable t) { + } catch (IndexOutOfBoundsException t) { // ignore } @@ -132,7 +133,7 @@ public static DatabaseDetails parse(final @Nullable String databaseConnectionUrl String path = StringUtils.removePrefix(url.getPath(), "/"); String pathWithoutProperties = StringUtils.substringBefore(path, ";"); return new DatabaseDetails(dbSystem, pathWithoutProperties); - } catch (Throwable t) { + } catch (URISyntaxException t) { // ignore } return new DatabaseDetails(dbSystem, null); diff --git a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OpenTelemetryAttributesExtractor.java b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OpenTelemetryAttributesExtractor.java index cf0fb06c11a..592d582349d 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OpenTelemetryAttributesExtractor.java +++ b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OpenTelemetryAttributesExtractor.java @@ -13,6 +13,7 @@ import io.sentry.util.HttpUtils; import io.sentry.util.StringUtils; import io.sentry.util.UrlUtils; +import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.List; @@ -94,7 +95,7 @@ private static Map collectHeaders( toString( CookieUtils.filterOutSecurityCookiesFromHeader( headerValues, headerName, null))); - } catch (Throwable t) { + } catch (ClassCastException t) { options .getLogger() .log(SentryLevel.WARNING, "Expected a List as header", t); @@ -143,7 +144,7 @@ private static Map collectHeaders( } else { return new URL(scheme, serverAddress, serverPort.intValue(), pathToUse).toString(); } - } catch (Throwable t) { + } catch (MalformedURLException t) { options .getLogger() .log(SentryLevel.WARNING, "Unable to combine URL span attributes into one.", t); diff --git a/sentry-opentelemetry/sentry-opentelemetry-otlp/src/main/java/io/sentry/opentelemetry/otlp/OpenTelemetryOtlpPropagator.java b/sentry-opentelemetry/sentry-opentelemetry-otlp/src/main/java/io/sentry/opentelemetry/otlp/OpenTelemetryOtlpPropagator.java index 4cdf1b0ed09..e11fce13e76 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-otlp/src/main/java/io/sentry/opentelemetry/otlp/OpenTelemetryOtlpPropagator.java +++ b/sentry-opentelemetry/sentry-opentelemetry-otlp/src/main/java/io/sentry/opentelemetry/otlp/OpenTelemetryOtlpPropagator.java @@ -25,6 +25,7 @@ import io.sentry.exception.InvalidSentryTraceHeaderException; import io.sentry.util.PropagationTargetsUtils; import io.sentry.util.TracingUtils; +import java.net.MalformedURLException; import java.net.URL; import java.util.Arrays; import java.util.Collection; @@ -123,7 +124,7 @@ private boolean shouldInjectTracingHeaders(final @NotNull Span otelSpan) { } else { return new URL(scheme, serverAddress, serverPort.intValue(), pathToUse).toString(); } - } catch (Throwable t) { + } catch (MalformedURLException t) { options .getLogger() .log(SentryLevel.WARNING, "Unable to combine URL span attributes into one.", t); diff --git a/sentry/src/main/java/io/sentry/Baggage.java b/sentry/src/main/java/io/sentry/Baggage.java index e4777bd063e..c8d8a0118ae 100644 --- a/sentry/src/main/java/io/sentry/Baggage.java +++ b/sentry/src/main/java/io/sentry/Baggage.java @@ -146,7 +146,10 @@ public static Baggage fromHeader( if (!DSCKeys.SAMPLE_RAND.equalsIgnoreCase(key)) { shouldFreeze = true; } - } catch (Throwable e) { + } catch (UnsupportedEncodingException + | IllegalArgumentException + | IndexOutOfBoundsException e) { + // e.g. an entry without "=", or an invalid percent-encoding logger.log( SentryLevel.ERROR, e, @@ -315,7 +318,7 @@ public String getThirdPartyHeader() { sb.append(encodedKeyValue); separator = ","; } - } catch (Throwable e) { + } catch (UnsupportedEncodingException e) { logger.log( SentryLevel.ERROR, e, diff --git a/sentry/src/main/java/io/sentry/EnvelopeSender.java b/sentry/src/main/java/io/sentry/EnvelopeSender.java index 9f630fc2602..06bcaf88e64 100644 --- a/sentry/src/main/java/io/sentry/EnvelopeSender.java +++ b/sentry/src/main/java/io/sentry/EnvelopeSender.java @@ -128,7 +128,7 @@ private void safeDelete(final @NotNull File file, final @NotNull String errorMes file.getAbsolutePath(), errorMessageSuffix); } - } catch (Throwable e) { + } catch (SecurityException e) { logger.log( SentryLevel.ERROR, e, diff --git a/sentry/src/main/java/io/sentry/FilterString.java b/sentry/src/main/java/io/sentry/FilterString.java index 3fd146aa4eb..9d49ebcd0e5 100644 --- a/sentry/src/main/java/io/sentry/FilterString.java +++ b/sentry/src/main/java/io/sentry/FilterString.java @@ -2,6 +2,7 @@ import java.util.Objects; import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,7 +15,7 @@ public FilterString(@NotNull String filterString) { @Nullable Pattern pattern = null; try { pattern = Pattern.compile(filterString); - } catch (Throwable t) { + } catch (PatternSyntaxException t) { Sentry.getCurrentScopes() .getOptions() .getLogger() diff --git a/sentry/src/main/java/io/sentry/MonitorSchedule.java b/sentry/src/main/java/io/sentry/MonitorSchedule.java index 438e0399632..a065dfc15ea 100644 --- a/sentry/src/main/java/io/sentry/MonitorSchedule.java +++ b/sentry/src/main/java/io/sentry/MonitorSchedule.java @@ -100,7 +100,7 @@ public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger if (MonitorScheduleType.INTERVAL.apiName().equalsIgnoreCase(type)) { try { writer.name(JsonKeys.VALUE).value(Integer.valueOf(value)); - } catch (Throwable t) { + } catch (NumberFormatException t) { logger.log(SentryLevel.ERROR, "Unable to serialize monitor schedule value: %s", value); } } else { diff --git a/sentry/src/main/java/io/sentry/Sentry.java b/sentry/src/main/java/io/sentry/Sentry.java index 932569177b4..4cc64060e26 100644 --- a/sentry/src/main/java/io/sentry/Sentry.java +++ b/sentry/src/main/java/io/sentry/Sentry.java @@ -32,6 +32,7 @@ import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; @@ -490,7 +491,7 @@ private static void handleAppStartProfilingConfig( options.getSerializer().serialize(appStartProfilingOptions, writer); } } - } catch (Throwable e) { + } catch (IOException e) { options .getLogger() .log( @@ -498,7 +499,7 @@ private static void handleAppStartProfilingConfig( } } }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options .getLogger() .log( @@ -523,7 +524,7 @@ private static void movePreviousSession(final @NotNull SentryOptions options) { // enqueue a task to move previous unfinished session to its own file try { options.getExecutorService().submit(new MovePreviousSession(options)); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.DEBUG, "Failed to move previous session.", e); } } @@ -536,7 +537,7 @@ private static void finalizePreviousSession( // to modify the previous session have done their work, even if they do that async. try { options.getExecutorService().submit(new PreviousSessionFinalizer(options, scopes)); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.DEBUG, "Failed to finalize previous session.", e); } } @@ -579,7 +580,7 @@ private static void notifyOptionsObservers(final @NotNull SentryOptions options) } } }); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { options.getLogger().log(SentryLevel.DEBUG, "Failed to notify options observers.", e); } } diff --git a/sentry/src/main/java/io/sentry/SentryCrashLastRunState.java b/sentry/src/main/java/io/sentry/SentryCrashLastRunState.java index dc5b334df25..d086e5b3027 100644 --- a/sentry/src/main/java/io/sentry/SentryCrashLastRunState.java +++ b/sentry/src/main/java/io/sentry/SentryCrashLastRunState.java @@ -53,7 +53,7 @@ public static SentryCrashLastRunState getInstance() { nativeMarker.delete(); } } - } catch (Throwable e) { + } catch (SecurityException e) { // ignore // TODO: Take ILogger via ctor and log here } diff --git a/sentry/src/main/java/io/sentry/SentryOptions.java b/sentry/src/main/java/io/sentry/SentryOptions.java index 71dd4588e33..0885eb44e4a 100644 --- a/sentry/src/main/java/io/sentry/SentryOptions.java +++ b/sentry/src/main/java/io/sentry/SentryOptions.java @@ -2519,7 +2519,7 @@ public void setOrgId(final @Nullable String orgId) { try { final @Nullable String dsnOrgId = retrieveParsedDsn().getOrgId(); return dsnOrgId; - } catch (Throwable e) { + } catch (IllegalArgumentException e) { return null; } } diff --git a/sentry/src/main/java/io/sentry/SentryTracer.java b/sentry/src/main/java/io/sentry/SentryTracer.java index ad130ac55a9..06b2822025f 100644 --- a/sentry/src/main/java/io/sentry/SentryTracer.java +++ b/sentry/src/main/java/io/sentry/SentryTracer.java @@ -15,6 +15,7 @@ import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import org.jetbrains.annotations.ApiStatus; @@ -122,7 +123,7 @@ public void scheduleFinish() { .getOptions() .getTimerExecutorService() .schedule(this::onIdleTimeoutReached, idleTimeout); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { scopes .getOptions() .getLogger() @@ -314,7 +315,7 @@ private void scheduleDeadlineTimeout() { .getOptions() .getTimerExecutorService() .schedule(this::onDeadlineTimeoutReached, deadlineTimeOut); - } catch (Throwable e) { + } catch (RejectedExecutionException e) { scopes .getOptions() .getLogger() diff --git a/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java b/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java index d3f473cfbc9..9a7d3385a6e 100644 --- a/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java +++ b/sentry/src/main/java/io/sentry/cache/EnvelopeCache.java @@ -285,7 +285,7 @@ private void writeCrashMarkerFile() { final String timestamp = DateUtils.getTimestamp(DateUtils.getCurrentDateTime()); outputStream.write(timestamp.getBytes(UTF_8)); outputStream.flush(); - } catch (Throwable e) { + } catch (IOException e) { options.getLogger().log(ERROR, "Error writing the crash marker file to the disk", e); } } @@ -376,7 +376,7 @@ private boolean writeSessionToDisk(final @NotNull File file, final @NotNull Sess .log(DEBUG, "Overwriting session to offline storage: %s", session.getSessionId()); serializer.getValue().serialize(session, writer); - } catch (Throwable e) { + } catch (IOException e) { options .getLogger() .log(ERROR, e, "Error writing Session to offline storage: %s", session.getSessionId()); @@ -529,7 +529,7 @@ public void movePreviousSession( if (!renamed) { options.getLogger().log(WARNING, "Unable to move current session to previous session."); } - } catch (Throwable e) { + } catch (SecurityException e) { options .getLogger() .log(SentryLevel.ERROR, "Error moving current session to previous session.", e); diff --git a/sentry/src/main/java/io/sentry/cache/PersistingScopeObserver.java b/sentry/src/main/java/io/sentry/cache/PersistingScopeObserver.java index 756f36f65da..a4b1269390b 100644 --- a/sentry/src/main/java/io/sentry/cache/PersistingScopeObserver.java +++ b/sentry/src/main/java/io/sentry/cache/PersistingScopeObserver.java @@ -35,6 +35,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicBoolean; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -246,7 +247,7 @@ private void requestFlush() { // no later mutation would ever be able to queue a flush again hasPendingFlush.set(false); } - } catch (Throwable e) { + } catch (RejectedExecutionException e) { hasPendingFlush.set(false); options.getLogger().log(ERROR, "Scope persistence flush could not be submitted", e); } diff --git a/sentry/src/main/java/io/sentry/config/FilesystemPropertiesLoader.java b/sentry/src/main/java/io/sentry/config/FilesystemPropertiesLoader.java index c896091f006..a87ebc4bc33 100644 --- a/sentry/src/main/java/io/sentry/config/FilesystemPropertiesLoader.java +++ b/sentry/src/main/java/io/sentry/config/FilesystemPropertiesLoader.java @@ -5,6 +5,7 @@ import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; +import java.io.IOException; import java.io.InputStream; import java.util.Properties; import org.jetbrains.annotations.NotNull; @@ -50,7 +51,7 @@ public FilesystemPropertiesLoader( "Failed to load Sentry configuration since it is not readable: %s", filePath); } - } catch (Throwable e) { + } catch (IOException | IllegalArgumentException e) { logger.log( SentryLevel.ERROR, e, "Failed to load Sentry configuration from file: %s", filePath); return null; diff --git a/sentry/src/main/java/io/sentry/internal/modules/ManifestModulesLoader.java b/sentry/src/main/java/io/sentry/internal/modules/ManifestModulesLoader.java index fc1c313ec43..d4889147293 100644 --- a/sentry/src/main/java/io/sentry/internal/modules/ManifestModulesLoader.java +++ b/sentry/src/main/java/io/sentry/internal/modules/ManifestModulesLoader.java @@ -4,6 +4,7 @@ import io.sentry.ILogger; import io.sentry.SentryLevel; +import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; @@ -57,7 +58,7 @@ protected Map loadModules() { modules.add(module); } } - } catch (Throwable e) { + } catch (IOException e) { logger.log(SentryLevel.ERROR, "Unable to detect modules via manifest files.", e); } diff --git a/sentry/src/main/java/io/sentry/util/Platform.java b/sentry/src/main/java/io/sentry/util/Platform.java index bad0f214db3..a46e816311c 100644 --- a/sentry/src/main/java/io/sentry/util/Platform.java +++ b/sentry/src/main/java/io/sentry/util/Platform.java @@ -15,7 +15,7 @@ public final class Platform { // All system properties on Android: // https://developer.android.com/reference/java/lang/System#getProperties() isAndroid = "The Android Project".equals(System.getProperty("java.vendor")); - } catch (Throwable e) { + } catch (SecurityException e) { isAndroid = false; } @@ -31,7 +31,7 @@ public final class Platform { } else { isJavaNinePlus = false; } - } catch (Throwable e) { + } catch (SecurityException | NumberFormatException e) { isJavaNinePlus = false; } } diff --git a/sentry/src/test/java/io/sentry/cache/EnvelopeCacheTest.kt b/sentry/src/test/java/io/sentry/cache/EnvelopeCacheTest.kt index 0cc2c968195..591b89e4959 100644 --- a/sentry/src/test/java/io/sentry/cache/EnvelopeCacheTest.kt +++ b/sentry/src/test/java/io/sentry/cache/EnvelopeCacheTest.kt @@ -24,6 +24,7 @@ import io.sentry.hints.SessionStartHint import io.sentry.protocol.SentryId import io.sentry.util.HintUtils import java.io.File +import java.io.IOException import java.io.Writer import java.nio.file.Files import java.nio.file.Path @@ -335,7 +336,7 @@ class EnvelopeCacheTest { val delayedStart = createSession(sessionId = sid) val serializer = mock() whenever(serializer.serialize(same(liveSession), any())) - .thenThrow(RuntimeException("forced ex")) + .thenThrow(IOException("forced ex")) whenever(serializer.deserialize(any(), eq(Session::class.java))).thenReturn(delayedStart) val cache = fixture.getSUT { options -> options.setSerializer(serializer) }