Build issues
UnsatisfiedLinkError: dlopen failed: library not found
UnsatisfiedLinkError: dlopen failed: library not found
This error occurs when the dynamic linker cannot find a required shared library.Common causes:
- Library not packaged in the APK
- ABI mismatch (e.g., loading arm64-v8a library on armeabi-v7a device)
- Incorrect library name
- Missing dependencies
- Verify the library exists in your APK:
- Check that you’re building for the correct ABIs:
- Ensure library name matches exactly:
- Check for missing dependencies:
UnsatisfiedLinkError: No implementation found for native method
UnsatisfiedLinkError: No implementation found for native method
The JNI method signature in your C/C++ code doesn’t match the Java declaration.Common causes:
- Incorrect function name
- Wrong package or class name in JNI function
- Missing
extern "C"in C++ - Method not registered
- Generate the correct signature:
- Verify your JNI function name:
- Use
extern "C"for C++ code:
- Alternative: Use dynamic registration:
Build fails with 'text relocations' error
Build fails with 'text relocations' error
Text relocations are not allowed on Android 6.0+ (API level 23) for security reasons.Error message:Cause:
Code was not compiled as position-independent code (PIC).Solution:Ensure you’re using Or check your existing libraries:If third-party libraries have text relocations, contact the vendor for an updated version.
-fPIC flag:Undefined reference to symbol
Undefined reference to symbol
The linker cannot find the implementation of a function or variable.Common causes:
- Missing library in link command
- Wrong link order
- Symbol not exported
- C++ name mangling issues
- Add the required library:
- Check symbol availability:
- Fix C++ name mangling:
- Check symbol visibility:
CMake cannot find Android NDK
CMake cannot find Android NDK
CMake can’t locate your NDK installation.Solutions:
- Set
ANDROID_NDKenvironment variable:
- Specify in CMake command:
- Use Android Gradle Plugin (recommended):
Runtime issues
Crashes with SIGSEGV (segmentation fault)
Crashes with SIGSEGV (segmentation fault)
The most common native crash. Your code accessed invalid memory.Common causes:
- Null pointer dereference
- Use after free
- Buffer overflow
- Stack overflow
- Invalid JNI reference
- Get the tombstone (see Understanding crashes)
- Use Address Sanitizer:
- Check JNI usage:
- Use Android Studio’s native debugger
Crashes with SIGABRT (abort)
Crashes with SIGABRT (abort)
Your code or a library called Look at the stack trace to identify the failing assertion or error.
abort(), often due to assertion failures or critical errors.Common causes:- Failed assertion (
assert()orCHECK()) - Memory allocation failure
- Fatal error in C++ standard library
- Stack smashing detected
Memory leaks in native code
Memory leaks in native code
Native memory is not garbage collected. You must manually free allocated memory.Detection:Use Address Sanitizer with leak detection:Common leak patterns:
- Missing
free()ordelete:
- JNI reference leaks:
JNI local reference table overflow
JNI local reference table overflow
You’ve created too many JNI local references without deleting them.Error:Solution:
- Delete local references when done:
- Use
PushLocalFrame/PopLocalFramefor bulk cleanup:
Threading issues and race conditions
Threading issues and race conditions
Multiple threads accessing shared data without synchronization.Detection:Use Thread Sanitizer:Solutions:
- Use mutexes:
- Use atomic operations:
- Remember: Each thread needs its own
JNIEnv*:
Platform-specific issues
Works on emulator but crashes on device
Works on emulator but crashes on device
The emulator and physical devices can have different characteristics.Common causes:
- ABI mismatch (emulator is x86, device is ARM)
- Uninitialized memory (different initial values)
- Timing issues (emulator is slower)
- Hardware features (NEON, SSE)
- Test on actual hardware early
- Use sanitizers to catch undefined behavior
- Check CPU features before using SIMD:
Different behavior on different Android versions
Different behavior on different Android versions
Android’s C library (bionic) and system behavior evolve over time.Solutions:
- Check API level at runtime:
- Review Android changes for NDK developers
- Test on multiple Android versions
App works on 32-bit but fails on 64-bit
App works on 32-bit but fails on 64-bit
Type size assumptions or ABI issues.Common causes:
- Assuming
intand pointers are same size - Assuming
longis 32 bits - Structure packing differences
- Inline assembly for wrong architecture
Performance issues
Slow JNI calls
Slow JNI calls
Frequent JNI calls have overhead.Solutions:
- Batch operations:
- Cache JNI method IDs and field IDs:
- Use direct buffer access:
Excessive memory usage
Excessive memory usage
Native code uses too much memory.Solutions:
- Use tools to analyze:
- Reuse buffers:
- Free large allocations promptly
- Consider memory mapping for large files
Getting help
If you’re still stuck:- Check tombstone files (see Understanding crashes)
- Enable detailed logging
- Search android-ndk GitHub issues
- Ask on android-ndk Google Group
- Review bionic documentation