Skip to main content
An Application Binary Interface (ABI) defines the machine code interface for your native libraries. Understanding ABIs is crucial for distributing Android applications with native code across different device architectures.

What is an ABI?

An ABI specifies:
  • Instruction set: The CPU architecture (ARM, x86, RISC-V)
  • Calling conventions: How functions receive parameters and return values
  • Register usage: Which CPU registers are used for what purposes
  • Memory layout: Data structure sizes, alignment, and byte ordering
  • System call interface: How to invoke kernel functionality
When you compile native code, you must specify the target ABI. The resulting .so file will only run on devices with that ABI.

Supported ABIs

Android NDK supports the following ABIs:

arm64-v8a

Architecture: ARMv8-A 64-bitUsage: Modern Android devices (Android 5.0+)Characteristics:
  • 64-bit architecture with larger address space
  • Access to more CPU registers (31 general-purpose registers)
  • Advanced SIMD with NEON (128-bit vectors)
  • Hardware cryptography extensions
  • Most common ABI for recent Android devices
Typical devices:
  • Flagship phones from 2015 onwards
  • Mid-range and budget phones from 2017 onwards
  • All devices shipping with Android 10+
# CMakeLists.txt
set(CMAKE_ANDROID_ARCH_ABI arm64-v8a)
As of 2024, arm64-v8a is the dominant ABI, representing over 85% of active Android devices.

Deprecated ABIs

The following ABIs are no longer supported:
ABIRemovedNotes
armeabiNDK r17Generic ARMv5TE, very old devices
mipsNDK r17MIPS 32-bit, never widely adopted
mips64NDK r17MIPS 64-bit, never widely adopted
If your app targets these ABIs, you must upgrade to supported ABIs or use an older NDK version (not recommended).

ABI compatibility

Fallback behavior

Android can run 32-bit libraries on 64-bit devices:
  • arm64-v8a devices can run armeabi-v7a libraries
  • x86_64 devices can run x86 libraries
If your APK contains any 64-bit library, Android will only load 64-bit libraries. Mixing ABIs within a single APK requires providing all libraries for all included ABIs.
// If you have arm64-v8a libraries, you must provide ALL libraries
// for arm64-v8a. Android won't fall back to armeabi-v7a versions.
android {
    defaultConfig {
        ndk {
            // Ensure all libraries exist for these ABIs
            abiFilters 'arm64-v8a', 'armeabi-v7a'
        }
    }
}

Library dependencies

All native dependencies must match ABIs:
app/src/main/jniLibs/
├── arm64-v8a/
│   ├── libnative.so      ✓ Your library
│   └── libdependency.so  ✓ Must include dependency
└── armeabi-v7a/
    ├── libnative.so      ✓ Your library
    └── libdependency.so  ✓ Must include dependency

APK configuration strategies

Fat APKs (single APK)

One APK containing libraries for all ABIs:
  • Simple distribution (one APK for all devices)
  • No app bundle required
  • Works with all distribution channels
  • Easier version management
// build.gradle - Fat APK with multiple ABIs
android {
    defaultConfig {
        ndk {
            abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86_64', 'x86'
        }
    }
}
Typical APK size impact:
Base APK: 5 MB
+ arm64-v8a libs: 3 MB
+ armeabi-v7a libs: 2.5 MB
+ x86_64 libs: 3.2 MB
+ x86 libs: 2.8 MB
= Total: 16.5 MB (users download all)

Split APKs (multiple APKs)

Generate separate APKs per ABI:
  • Smaller download size per device
  • Users only get required ABI
  • Reduced storage on device
// build.gradle - Split APKs
android {
    splits {
        abi {
            enable true
            reset()
            include 'arm64-v8a', 'armeabi-v7a', 'x86_64', 'x86'
            universalApk true  // Also generate fat APK
        }
    }
    
    // Version codes for different ABIs
    android.applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def abiVersionCode = 0
            switch (output.getFilter("ABI")) {
                case "arm64-v8a": abiVersionCode = 1; break
                case "armeabi-v7a": abiVersionCode = 2; break
                case "x86_64": abiVersionCode = 3; break
                case "x86": abiVersionCode = 4; break
            }
            output.versionCodeOverride = 
                abiVersionCode * 1000000 + defaultConfig.versionCode
        }
    }
}
Google Play generates optimized APKs per device:
  • Automatic optimization by Google Play
  • Smallest possible download size
  • Users get only their device’s ABI
  • Simplest configuration
  • Supports dynamic delivery
// build.gradle - App Bundle (default, no special config needed)
android {
    defaultConfig {
        ndk {
            // Include all ABIs, Play Store delivers appropriate one
            abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86_64', 'x86'
        }
    }
}
# Build App Bundle
./gradlew bundleRelease

# Output: app/build/outputs/bundle/release/app-release.aab
App Bundle is the recommended approach for Google Play distribution. Users automatically receive the optimal APK for their device.
For most applications in 2024:
Only support 64-bit ARM:
android {
    defaultConfig {
        ndk {
            abiFilters 'arm64-v8a'
        }
    }
}
Coverage: ~85-90% of active devicesRationale:
  • Smallest APK size
  • All Android 10+ devices
  • Trade off: Excludes older/budget devices
Support all major ABIs:
android {
    defaultConfig {
        ndk {
            abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86_64', 'x86'
        }
    }
}
Coverage: Nearly 100% of devicesRationale:
  • Maximum device compatibility
  • Supports emulators natively
  • Chrome OS devices
  • Trade off: Larger APK (use App Bundle to mitigate)
For development builds:
android {
    buildTypes {
        debug {
            ndk {
                // Only build for your test device/emulator
                abiFilters 'arm64-v8a'  // or 'x86_64' for emulator
            }
        }
        release {
            ndk {
                abiFilters 'arm64-v8a', 'armeabi-v7a'
            }
        }
    }
}
Rationale:
  • Faster build times during development
  • Full ABI coverage for release builds

Detecting ABI at runtime

You can check which ABI your app is running on:
import android.os.Build

fun getCurrentABI(): String {
    return Build.SUPPORTED_ABIS[0]
}

fun getAllSupportedABIs(): Array<String> {
    return Build.SUPPORTED_ABIS
}

fun isArm64(): Boolean {
    return Build.SUPPORTED_ABIS[0] == "arm64-v8a"
}

// Example usage
val abi = getCurrentABI()
Log.d("ABI", "Running on: $abi")
// Output: "Running on: arm64-v8a"
Build.CPU_ABI and Build.CPU_ABI2 are deprecated. Use Build.SUPPORTED_ABIS instead.

ABI-specific optimizations

You can write ABI-specific code using compiler defines:
#include <android/ndk-version.h>

void optimized_function(float* data, int length) {
#if defined(__aarch64__)  // arm64-v8a
    // Use ARM NEON 64-bit optimizations
    #include <arm_neon.h>
    // NEON implementation...
    
#elif defined(__ARM_NEON__)  // armeabi-v7a with NEON
    // Use ARM NEON 32-bit optimizations
    #include <arm_neon.h>
    // NEON implementation...
    
#elif defined(__x86_64__) || defined(__i386__)  // x86/x86_64
    // Use SSE/AVX optimizations
    #include <xmmintrin.h>
    // SSE implementation...
    
#else
    // Generic C implementation
    for (int i = 0; i < length; i++) {
        data[i] = process(data[i]);
    }
#endif
}

Troubleshooting

Error: UnsatisfiedLinkError: dalvik.system.PathClassLoader couldn't find "libnative.so"Causes:
  1. Library not built for device’s ABI
  2. Missing dependencies for that ABI
  3. Library in wrong directory
Solutions:
# Check which ABIs are in your APK
unzip -l app-release.apk | grep "\.so$"

# Should see:
# lib/arm64-v8a/libnative.so
# lib/armeabi-v7a/libnative.so
Verify your build.gradle includes the target ABI:
ndk {
    abiFilters 'arm64-v8a', 'armeabi-v7a'
}
Error: App crashes on 64-bit devices but works on 32-bitCause: APK contains arm64-v8a libraries but missing some dependencies in arm64-v8aSolution: Ensure all native libraries exist for all included ABIs:
# Check library consistency
unzip -l app.apk | grep "\.so$" | sort

# Should have matching files for each ABI:
# lib/arm64-v8a/libnative.so
# lib/arm64-v8a/libdep.so
# lib/armeabi-v7a/libnative.so  
# lib/armeabi-v7a/libdep.so
Problem: APK too large with multiple ABIsSolutions:
  1. Use Android App Bundle (recommended)
  2. Use APK splits
  3. Remove unnecessary ABIs (x86/x86_64 if not needed)
  4. Use ProGuard/R8 to remove unused code
// Optimize library size
android {
    buildTypes {
        release {
            minifyEnabled true
            
            // Strip debug symbols
            packagingOptions {
                doNotStrip '*/arm64-v8a/*.so'
                doNotStrip '*/armeabi-v7a/*.so'
            }
        }
    }
}

Next steps

For the latest ABI support and device statistics, check the Android Developer Dashboard.

Build docs developers (and LLMs) love