diff --git a/CHANGELOG.md b/CHANGELOG.md index a18600c6085..cf0d89cca02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Deprecate `enableTracing` option ([#3777](https://github.com/getsentry/sentry-java/pull/3777)) - Vendor `java.util.Random` and replace `java.security.SecureRandom` usages ([#3783](https://github.com/getsentry/sentry-java/pull/3783)) - Fix potential ANRs due to NDK scope sync ([#3754](https://github.com/getsentry/sentry-java/pull/3754)) +- Fix potential ANRs due to NDK System.loadLibrary calls ([#3670](https://github.com/getsentry/sentry-java/pull/3670)) ## 7.15.0 diff --git a/sentry-android-ndk/src/main/java/io/sentry/android/ndk/SentryNdk.java b/sentry-android-ndk/src/main/java/io/sentry/android/ndk/SentryNdk.java index 1ddc04c5243..7245516b49b 100644 --- a/sentry-android-ndk/src/main/java/io/sentry/android/ndk/SentryNdk.java +++ b/sentry-android-ndk/src/main/java/io/sentry/android/ndk/SentryNdk.java @@ -1,23 +1,40 @@ package io.sentry.android.ndk; import io.sentry.android.core.SentryAndroidOptions; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @ApiStatus.Internal public final class SentryNdk { + private static final @NotNull CountDownLatch loadLibraryLatch = new CountDownLatch(1); + private SentryNdk() {} static { - // On older Android versions, it was necessary to manually call "`System.loadLibrary` on all - // transitive dependencies before loading [the] main library." - // The dependencies of `libsentry.so` are currently `lib{c,m,dl,log}.so`. - // See - // https://android.googlesource.com/platform/bionic/+/master/android-changes-for-ndk-developers.md#changes-to-library-dependency-resolution - System.loadLibrary("log"); - System.loadLibrary("sentry"); - System.loadLibrary("sentry-android"); + new Thread( + () -> { + // On older Android versions, it was necessary to manually call "`System.loadLibrary` + // on all + // transitive dependencies before loading [the] main library." + // The dependencies of `libsentry.so` are currently `lib{c,m,dl,log}.so`. + // See + // https://android.googlesource.com/platform/bionic/+/master/android-changes-for-ndk-developers.md#changes-to-library-dependency-resolution + try { + System.loadLibrary("log"); + System.loadLibrary("sentry"); + System.loadLibrary("sentry-android"); + } catch (Throwable t) { + // ignored + // if loadLibrary() fails, the later init() will throw an exception anyway + } finally { + loadLibraryLatch.countDown(); + } + }, + "SentryNdkLoadLibs") + .start(); } private static native void initSentryNative(@NotNull final SentryAndroidOptions options); @@ -31,14 +48,23 @@ private SentryNdk() {} */ public static void init(@NotNull final SentryAndroidOptions options) { SentryNdkUtil.addPackage(options.getSdkVersion()); - initSentryNative(options); + try { + if (loadLibraryLatch.await(2000, TimeUnit.MILLISECONDS)) { + initSentryNative(options); - // only add scope sync observer if the scope sync is enabled. - if (options.isEnableScopeSync()) { - options.addScopeObserver(new NdkScopeObserver(options)); - } + // only add scope sync observer if the scope sync is enabled. + if (options.isEnableScopeSync()) { + options.addScopeObserver(new NdkScopeObserver(options)); + } - options.setDebugImagesLoader(new DebugImagesLoader(options, new NativeModuleListLoader())); + options.setDebugImagesLoader(new DebugImagesLoader(options, new NativeModuleListLoader())); + } else { + throw new IllegalStateException("Timeout waiting for Sentry NDK library to load"); + } + } catch (InterruptedException e) { + throw new IllegalStateException( + "Thread interrupted while waiting for NDK libs to be loaded", e); + } } /** Closes the NDK integration */