Native code is compiled into binaries. Therefore, one set of binaries can only run on a specific architecture. Android NDK comes with techniques and tools to allow developers to compile the same source code for multiple architectures easily.
An Application Binary Interface (ABI) defines how the Android application's machine code is supposed to interact with the system at runtime, including the CPU instruction set, endianness, alignment of memory, and so on. An ABI basically defines a type of architecture.
The following table briefly summarizes the four ABIs supported by Android:
ABI name |
Support |
Not support |
Optional |
---|---|---|---|
|
Hardware-assisted floating point computation | ||
|
| ||
|
| ||
|
|
armeabi and armeabi-v7a are the two most commonly used ABIs for Android devices. ABI armeabi-v7a is compatible with armeabi, which means applications compiled for armeabi can run on armeabi-v7a too. But the reverse is not true, since armeabi-v7a includes additional features. In the following section, we briefly introduce some technical terms referred to frequently in armeabi and armeabi-v7a:
Thumb-2 extends Thumb-1 by adding some 32-bit instructions, which results in a variable-length instruction set. Thumb-2 aims to attain code density like to Thumb-1 and performance similar to standard ARM instruction set on a 32-bit memory.
Android NDK generates the thumb code by default, unless LOCAL_ARM_MODE
is defined in the Android.mk
file.
One can refer to ARM documentation website at http://infocenter.arm.com/help/index.jsp for more detailed information. We don't discuss x86 and mips ABI here, because few Android devices run on these architecture.
Read the Building Android NDK Application at Eclipse recipe before going through this one.
The following steps build an Android project for different ABIs:
HelloNDKMultipleABI
. Set the package name as cookbook.chapter3
. Create an activity named HelloNDKMultipleABIActivity
.HelloNDKMultipleABI
project, select Android Tools | Add Native Support. A window appears, click on Finish to dismiss it. This will add a jni
folder with two files (HelloNDKMultipleABI.cpp
and Android.mk
) inside, and switch Eclipse to the C/C++ perspective.HelloNDKMultipleABI.cpp
file:#include <jni.h> jstring getString(JNIEnv* env) { return env->NewStringUTF("Hello NDK"); } extern "C" { JNIEXPORT jstring JNICALL Java_cookbook_chapter3_HelloNDKMultipleABIActivity_getString(JNIEnv* env, jobject o){ return getString(env); } }
HelloNDKMultipleABIActivity.java
file to the following content:package cookbook.chapter3; import android.os.Bundle; import android.app.Activity; import android.widget.TextView; public class HelloNDKMultipleABIActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView tv = new TextView(this); tv.setTextSize(30); tv.setText(getString()); this.setContentView(tv); } public native String getString(); static { System.loadLibrary("HelloNDKMultipleABI"); } }
Application.mk
under the project's jni
folder with the following content:APP_ABI := armeabi armeabi-v7a
HelloNDKMultipleABIActivity
project, and select Build Project. This will build the native library for us.armeabi
and armeabi-v7a
respectively. The following screenshot depicts how an emulator is created with the armeabi
ABI:Application.mk
to the following code snippet and run the sample application on the two emulators. The application will still work on both the emulators:#APP_ABI := armeabi armeabi-v7a APP_ABI := armeabi
Application.mk
as follows:#APP_ABI := armeabi armeabi-v7a #APP_ABI := armeabi APP_ABI := armeabi-v7a
armeabi-v7a
emulator, but crashes on armeabi
emulator, as shown in the following screenshot:An Android device can define one or two ABIs. For typical x86-, MIPS-, ARMv5-, and ARMv6-based devices, there's only a primary ABI. Based on the platform, it can be x86, mips, or armeabi. For a typical ARMv7-based device, the primary ABI is usually armeabi-v7a, and it also has a secondary ABI as armeabi. This enables binaries compiled for either armeabi or armeabi-v7a to run on ARMv7 devices. In our example, we demonstrated that the app can work on both armeabi and armeabi-v7a emulators when built against only armeabi.
At installation, the Android package manager searches for native libraries built for the primary ABI and copies them to the application's data directory. If not found, it then searches the native libraries built for the secondary ABI. This ensures that only the proper native libraries are installed.
In our example, when we compile the binary against armeabi-v7a only, the native library won't get installed on the armeabi emulator, subsequently the native library cannot be loaded, and a crash will be shown.