There are many reasons why to write your algorithm in assembler. You can have all the optimizations firmly in hand. However, it comes at costs – you need to know a lot about the hardware running your program, your program will be highly non-portable, non readable and you will spend ages on writing it. Oh, did I mention that debugging is a hell?
Preparation
So, to start using assembly in Android Studio, you need to install Android NDK. You can install it manually (and reference the installation) or from the Android Studio itself ( File > Settings > Appearence & Behaviour > System Settings > Android SDK > SDK Tools
).
Check your Android NDK installation path. In case you installed in from Android studio, it will most likely be located at path:
$(ANDROID_SDK)\ndk-bundle
You are going to need the location to run some commands.
The good thing is that the android NDK comes with all necessary tools, like the assembly compiler and cmake, built-in – so you don’t have to install anything else.
We are going to make a simple implementation of the sum function in assembly, and we are going to target only one platform (armeabi-v7a).
Writing your first assembly app
Here are the individual steps:
- Create an empty project, and name it AsmSum. The important step it to check Include C++ support. You can select the desired platform and an empty activity. For the purpose of the example, we assume a phone or a tablet app based on armeabi-v7a.
- Open your application gradle file and add abiFilter to your ndk settings and specify your compiler. Since the instruction set varies among different processors and platform, in this tutorial we focus on one platform, being armeabi-v7a and compiler gcc:
android { defaultConfig { ... ndk { abiFilters 'armeabi-v7a' } externalNativeBuild { cmake { arguments '-DANDROID_TOOLCHAIN=gcc' } } ... } ... }
- Now we need to add/create the assembly file. Create a file in the path
$(PROJECT)/src/main/cpp/multiply.s
. This file will not be visible through the Android studio, unfortunately, it does not support assembly files yet (my best guess is it never will).
@ This file is multiply.s .text .align 2 .global multiply .type multiply, %function multiply: @ Multiply the arguments in registers r0 and r1 stmfd sp!, {fp,ip,lr} mul r0, r1, r0 ldmfd sp!, {fp,ip,lr} bx lr .size multiply, .-multiply
- Even though the assembly file multiply.s is not visible in the Android Studio, it is there and we need to instruct the building script to use it. For practical reasons, I recommend to create a separate native (static) library with your assembly code – by doing that you can easily separate code for different instruction sets. To create a separate library that will contain our
multiply.s
, add following lines to your cmake fileCMakeList.txt
.
set(can_use_assembler TRUE) enable_language(ASM) add_definitions(-DANDROID -DOC_ARM_ASM) add_library( multiply-lib STATIC src/main/cpp/multiply-lib.s )
- … and of course, link it to the final library
native-lib
that will be installed with the app:
target_link_libraries( native-lib multiply-lib ${log-lib} )
- The last task is to modify the C++ file with our JNI function to demonstrate the functionality of our assembly function. Since we created our assembly function in a C-like manner, we need to declare it to use it in a C++ files. In case you have more functions like this it might be handy to put these definitions into a separate header file.
#include <jni.h> #include <string> #include <android/log.h> extern "C" { jint multiply(jint a, jint b); } extern "C" JNIEXPORT jstring JNICALL Java_com_omelina_assembly_asmsum_MainActivity_stringFromJNI( JNIEnv *env, jobject /* this */) { __android_log_print(ANDROID_LOG_DEBUG,"NATIVE","%d ", multiply(6,7)); std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str()); }
- Tada … after compiling and running the project on a device you should see a log in the logcat window:
... 10-21 23:13:22.374 29816-29816/com.omelina.assembly.asmsum D/NATIVE: 42 ...
That is it. You just created a simple project demonstrating how to use assembly in an Android Studio project. The full source code can be found here.