Modernize build for Android API 36 + NDK 27, fix JNI class loader SIGABRT#21
Open
sharpninja wants to merge 1 commit intosevar83:masterfrom
Open
Modernize build for Android API 36 + NDK 27, fix JNI class loader SIGABRT#21sharpninja wants to merge 1 commit intosevar83:masterfrom
sharpninja wants to merge 1 commit intosevar83:masterfrom
Conversation
…ABRT
Build system:
- Upgrade AGP 3.6.0-alpha06 → 8.7.3, Gradle 5.6 → 8.11.1
- Replace deprecated jcenter() with mavenCentral()
- compileSdk/targetSdk 29 → 36, minSdk 16 → 21
- Java source/target 1.7 → 1.8
- Add pluginManagement block in settings.gradle
- Update AndroidX dependencies to current stable
- Update SQLite amalgamation to 3.49.1 (2025)
- Replace GradleScriptException with GradleException
NDK / native:
- APP_STL c++_shared → c++_static (eliminate libc++_shared.so APK dependency)
- APP_PLATFORM android-16 → android-21
- Drop armeabi-v7a from default ABIs (x86 already dropped)
- Replace deprecated APP_DEPRECATED_HEADERS / APP_SHORT_COMMANDS with
NDK_APP_SHORT_COMMANDS
- Add -Wno-incompatible-function-pointer-types to ndk-modules .mk files
(required by Clang 18+ in NDK r27)
JNI class loader fix (SIGABRT on .NET Android / Mono):
- Mono's DSO preload calls System.loadLibrary before any Java app code
runs, so JNI_OnLoad fires on the bootstrap class loader thread where
FindClass("org/spatialite/...") returns null → LOG_FATAL_IF → SIGABRT.
- JNI_OnLoad now only saves the JavaVM pointer.
- All RegisterNatives / FindClass / GetFieldID calls moved to a
std::call_once-guarded doLazyRegisterAll() invoked from nativeOpen(),
which always runs on an app Java thread with the app class loader.
- Replaced FIND_CLASS macro with direct env->FindClass() + LOG_FATAL_IF
in register_android_database_SQLiteConnection for clarity.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR brings android-spatialite up to date with current Android tooling (API 36, NDK r27, Gradle 8, AGP 8.7) and fixes a fatal SIGABRT that occurs when the library is loaded by non-standard runtimes such as .NET Android (Mono/Xamarin).
Build system modernization
jcenter()withmavenCentral()pluginManagementblock (required by Gradle 8)GradleScriptExceptionwithGradleExceptionNDK / native changes
APP_STLc++_sharedc++_staticlibc++_shared.soAPK dependency; avoids version conflicts when multiple native libraries ship in the same appAPP_PLATFORMandroid-16android-21APP_ABIarmeabi-v7a,arm64-v8a,x86,x86_64armeabi-v7a arm64-v8a x86_64APP_DEPRECATED_HEADERStrueAPP_SHORT_COMMANDStrueNDK_APP_SHORT_COMMANDS = trueAdded
-Wno-incompatible-function-pointer-typesto individual ndk-module.mkfiles where Clang 18+ (NDK r27) emits hard errors for legacy C function pointer casts in vendored source (freexl, geos, libiconv, liblzma, libspatialite, libxml2, proj.4).JNI class loader fix (critical — SIGABRT)
Problem: When
libandroid_spatialite.sois loaded by a non-standard runtime (e.g., .NET Android / Mono),System.loadLibraryfires before any Java application code runs.JNI_OnLoadtherefore executes on the bootstrap class loader thread, whereFindClass("org/spatialite/database/SQLiteCustomFunction")returnsNULL. The existing code callsLOG_FATAL_IF(!clazz, ...)which triggersabort()→ SIGABRT.This is specific to runtimes that preload native libraries during VM initialization (before the app class loader is available). Standard Android Java/Kotlin apps are unaffected because
SQLiteDatabase.<clinit>runs on an app thread.Fix:
JNI_OnLoadnow only saves theJavaVM*pointer — noRegisterNatives, noFindClass, noGetFieldID.register_android_database_SQLiteConnection,SQLiteGlobal,SQLiteDebug,CursorWindow) are called exactly once fromnativeOpen()viastd::call_once, which is the first native method invoked on an actual Java application thread where the app class loader is available.FIND_CLASSmacro with directenv->FindClass()+LOG_FATAL_IFinregister_android_database_SQLiteConnectionfor clarity and debuggability.This is fully backward-compatible: standard Java/Kotlin Android apps call
nativeOpen()on an app thread identically to before; the lazy registration is transparent.Test plan
libandroid_spatialite.sowithout SIGABRTnativeOpen()succeeds andRegisterNativescompletes on first database openmod_spatialiteextension loads viaSELECT load_extension('mod_spatialite')🤖 Generated with Claude Code