Overview
Starting with Android 5.0 (API level 21), Google began requiring 64-bit support. As of August 2019, all apps on Google Play must include 64-bit versions of native libraries alongside 32-bit versions. Understanding 32-bit ABI issues is still important for:- Maintaining legacy code
- Supporting older devices
- Debugging compatibility issues
- Ensuring correct migration to 64-bit
Common 32-bit ABI bugs
The following issues are specific to 32-bit Android ABIs (armeabi-v7a and x86).
time_t is 32-bit
On 32-bit Android,time_t is a 32-bit signed integer, leading to the Year 2038 problem.
time_twill overflow on January 19, 2038 at 03:14:07 UTC- Dates after 2038 cannot be represented
- Calculations involving future dates will fail
- Use 64-bit types for time calculations:
int64_torlong long - Migrate to 64-bit architecture (where
time_tis 64-bit) - For portable code, use C++20’s
std::chronoor custom time types
off_t is 32-bit by default
off_t (file offset type) is 32-bit by default on 32-bit Android, limiting files to 2GB.
_FILE_OFFSET_BITS=64 to use 64-bit file offsets:
stat structure differences
Thestat structure has different field sizes on 32-bit vs 64-bit:
- Serializing
statstructures - Passing them between 32-bit and 64-bit code
- Storing them in files or databases
stat64 explicitly on 32-bit:
Long double is the same as double
On 32-bit ARM,long double is only 64 bits (same as double), not 80 or 128 bits as on other platforms.
System calls use 32-bit parameters
Many system calls accept 32-bit parameters on 32-bit Android:- Maximum
mmap()size to 4GB - Maximum process memory to 4GB
- Various kernel resource limits
ABI-specific considerations
armeabi-v7a (32-bit ARM)
- Removed:
armeabi(non-Thumb ARM) was removed in NDK r17 - Supports NEON SIMD (check at runtime with
android_getCpuFeatures()) - Requires Thumb-2 instruction set
- Hardware floating-point support
x86 (32-bit Intel/AMD)
- Less common than ARM on Android devices
- Uses System V ABI calling conventions
- SIMD via SSE (check CPU features)
Migrating to 64-bit
Why migrate?
- Required by Google Play - Apps must support 64-bit
- Better performance - More registers, improved instruction set
- Larger address space - No 4GB memory limit
- Future-proof - 32-bit support may be deprecated
Migration checklist
Fix type assumptions
- Don’t assume
intand pointers are the same size - Don’t assume
longis 32 bits (it’s 64 bits on 64-bit) - Use
intptr_t,uintptr_tfor pointer-sized integers - Use
int32_t,int64_tfor explicit-width integers
Update third-party libraries
Ensure all native dependencies support 64-bit:
- Rebuild from source for 64-bit targets
- Update to latest versions that support 64-bit
- Check vendor documentation
Common migration issues
Pointer truncation
JNI type mismatches
Structure packing differences
Structure alignment and padding can differ between 32-bit and 64-bit:__attribute__((packed)) or explicit padding if binary compatibility is required.
Testing 32-bit and 64-bit builds
Run both ABIs
Test your app on both 32-bit and 64-bit devices:Check installed ABI
Force 32-bit on 64-bit device
For testing, you can force 32-bit mode:Performance considerations
Memory usage
64-bit apps use more memory due to:- Larger pointers (8 bytes vs 4 bytes)
- Increased structure padding
- Larger code size
Performance improvements
64-bit offers:- More CPU registers (32 vs 16 on ARM)
- Better instruction set (ARMv8 vs ARMv7)
- Hardware crypto acceleration
- Improved SIMD capabilities
Additional resources
- 32-bit ABI bugs documentation - Complete reference from AOSP
- Bionic status documentation - API differences between Android versions