diff --git a/CHANGELOG.md b/CHANGELOG.md index 3494f6f76d..cab90eb6b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ **Fixes**: - Crashpad: wait reliably for crash report uploads. ([#1885](https://github.com/getsentry/sentry-native/pull/1885)) +- Android: create the outbox directory before writing NDK crash envelopes into it, so envelopes are not lost when the head SDK creates the outbox lazily. ([#1889](https://github.com/getsentry/sentry-native/pull/1889)) ## 0.15.4 diff --git a/ndk/lib/CMakeLists.txt b/ndk/lib/CMakeLists.txt index 9bef5d7b3b..1b4153eda8 100644 --- a/ndk/lib/CMakeLists.txt +++ b/ndk/lib/CMakeLists.txt @@ -27,7 +27,10 @@ if(ENABLE_TESTS) endif() # Link to sentry-native -target_link_libraries(sentry-android PRIVATE $) +target_link_libraries(sentry-android PRIVATE + ${LOG_LIB} + $ +) # Support 16KB page sizes target_link_options(sentry-android PRIVATE "-Wl,-z,max-page-size=16384") diff --git a/ndk/lib/src/main/jni/sentry.c b/ndk/lib/src/main/jni/sentry.c index 2af6fc9cf8..8235a77824 100644 --- a/ndk/lib/src/main/jni/sentry.c +++ b/ndk/lib/src/main/jni/sentry.c @@ -1,8 +1,11 @@ +#include +#include #include #include #include #include #include +#include #define ENSURE(Expr) \ if (!(Expr)) \ @@ -308,6 +311,38 @@ Java_io_sentry_ndk_NativeScope_nativeClearAttachments(JNIEnv *env, jclass cls) sentry_clear_attachments(); } +// sentry-native's path helpers are internal to the core library and not +// exported from the shared object we link against, so we create the outbox +// ourselves. Android is always POSIX, so mkdir(2) is all we need. +static int +create_dir_all(const char *path) +{ + char *buf = sentry_malloc(strlen(path) + 1); + if (!buf) { + return -1; + } + strcpy(buf, path); + + int rv = 0; + for (char *p = buf; *p; p++) { + if (*p == '/' && p != buf) { + *p = '\0'; + if (mkdir(buf, 0700) != 0 && errno != EEXIST && errno != EINVAL) { + rv = -1; + goto done; + } + *p = '/'; + } + } + if (mkdir(buf, 0700) != 0 && errno != EEXIST && errno != EINVAL) { + rv = -1; + } + +done: + sentry_free(buf); + return rv; +} + static void send_envelope(sentry_envelope_t *envelope, void *data) { @@ -317,6 +352,14 @@ send_envelope(sentry_envelope_t *envelope, void *data) sentry_uuid_t envelope_id = sentry_uuid_new_v4(); sentry_uuid_as_string(&envelope_id, envelope_id_str); + // The head SDK may create the outbox lazily, so ensure it exists before + // writing into it; the underlying file write does not create parent + // directories and would otherwise silently fail. + if (create_dir_all(outbox_path) != 0) { + __android_log_print(ANDROID_LOG_ERROR, "sentry-native", + "failed to create outbox directory \"%s\"", outbox_path); + } + size_t outbox_len = strlen(outbox_path); size_t final_len = outbox_len + 42; // "/" + envelope_id_str + "\0" = 42 char *envelope_path = sentry_malloc(final_len); diff --git a/ndk/sample/src/main/java/io/sentry/ndk/sample/MainActivity.java b/ndk/sample/src/main/java/io/sentry/ndk/sample/MainActivity.java index fdef19d5aa..92d07b63d0 100644 --- a/ndk/sample/src/main/java/io/sentry/ndk/sample/MainActivity.java +++ b/ndk/sample/src/main/java/io/sentry/ndk/sample/MainActivity.java @@ -19,7 +19,9 @@ protected void onCreate(Bundle savedInstanceState) { } private void initNdk() { - final File outboxFolder = setupOutboxFolder(); + // The outbox directory is created by sentry-native, so we only need to + // hand it the path here. + final File outboxFolder = new File(getFilesDir(), "outbox"); final NdkOptions options = new NdkOptions( "https://1053864c67cc410aa1ffc9701bd6f93d@o447951.ingest.sentry.io/5428559", @@ -34,22 +36,4 @@ private void initNdk() { options.setTracesSampleRate(1); SentryNdk.init(options); } - - private File setupOutboxFolder() { - // ensure we have a proper outbox directory - final File outboxDir = new File(getFilesDir(), "outbox"); - if (outboxDir.isFile()) { - final boolean deleteOk = outboxDir.delete(); - if (!deleteOk) { - throw new IllegalStateException("Failed to delete outbox file: " + outboxDir); - } - } - if (!outboxDir.exists()) { - final boolean mkdirOk = outboxDir.mkdirs(); - if (!mkdirOk) { - throw new IllegalStateException("Failed to create outbox directory: " + outboxDir); - } - } - return outboxDir; - } }