Android applications can incorporate native code using the Native Development Kit (NDK) toolset. It allows developers to reuse legacy code, code to low-level hardware, or differentiate their apps by taking advantage of features otherwise not optimal or possible.
This article is a basic introduction on how to create NDK based apps for IA from start to finish, and also on simple use cases for porting existing NDK based apps to IA based devices. We will walk through a simple step-by-step app development scenario to demonstrate the process.
We assume you have already installed the Android development environment including the Android SDK, Android NDK and configured emulator-x86 to test the apps. Please refer to the Android Community section on Intel website for more information. To keep our development environment simple, we will use Linux* command line tools for the most part.
Creating NDK based Android App for IA based devices – Walkthrough of a simple App
Let’s assume we have some legacy code that uses C and assembly language to parse CPUID (please refer to http://en.wikipedia.org/wiki/CPUID for more on CPUID). Below is source listing for our “legacy” sample C code cupid.c (demo purposes only).
We would like call cupid_parse from our Android App (demo purpose only – cupid_parse function expects pre-allocated buffer) and display the output inside the App.
Following below is a step-by-step walk-through to create an Android App from start to finish, and to use the above legacy native code.
1. Creating Default Android Project
Android SDK has command line tools to generate default project structure for a typical hello world app. We will first create a default project, and then modify the java sources to add JNI calls and native code.
In the above screenshot, we first created a directory called labs/lab2 and used “android” command line tool to generate the default project. We specified android-15 as the API level, and named our app as “CPUIdApp” with package com.example.cpuid.
We then used the “ant” command line tool to build the project in debug mode and install using “adb” (or reinstall if exists on emulator or target). We assume you have already have an emulator or a device attached and it is the only listed device in “adb devices” command output.
Below is a screenshot of the Android x86 emulator with ICS after completing the above process.
Clicking on the App, you can see the default hello world output of the app. We will now modify the app to use native code.
2. Invoking Native code from java sources
The default android project generates the java sources for a typical hello world project with give package namespace (eg: com.example.cpuid). The screenshot below shows the source code generated for the main java source file.
To use native c/c code in our java source file, we first need to declare JNI call and load the native library, as highlighted yellow box in the screenshot below.
As seen in the declaration, the native call returns a java string which we can use anywhere in our java source. As shown in above screenshot, we modified the TextView to display the string we get from the native call. This is highlighted in red in the box.
This is a very simple case for declaring and using JNI native calls in Android App Java sources. Next, we will use “javah” tool to generate the JNI header stubs for native code, and add or modify native code to comply with JNI native headers.
3. Using “javah” to generate JNI header stubs for native code
We now have to modify our native code to comply with JNI call specification. “javah” too helps us automatically generate the appropriate JNI header stubs based on the Java source files. The “javah” tool requires the compiled Java class file for generating the headers. So we use the “ant” tool to quickly generate java class files as shown in below screenshot (“ant debug”).
Use “javah” to generate the jni header as shown in the screenshot (second yellow highlight box). It will create a directory “jni” and the header stub based on Java class. The screenshot below shows the generated JNI native header stub.
Create corresponding C source file (“com_example_cpuid_CPUIdApp.c”) for the above generated header. Following below is the source listing :
We call the native code cupid_parse and return the parsed buffer as JNI string. We are now ready to compile the native code using the x86 NDK toolset.
4. Building native code with NDK for x86
Please refer to the Android community section on Intel website (/en-us/articles/ndk-for-ia) for more information on NDK for IA installation and usage.
Android NDK toolset uses a build system, which requires a custom android specific make file “Android.mk” to be present in the “jni” folder of the project to compile native code. Android.mk specifies all the native C/C source files to be compiled, the headers and the type of build (eg: shared_library).
Below is the native code Android make listing for our project (“jni/Android.mk”)
This is a simple scenario with 2 C source files and specifies to build a shared library.
We can now issue “ndk-build APP_ABI=x86” to build our native code, and generate the shared lib. Android build system also provides another supplementary make file “Application.mk”, which we can use to specify additional configuration options. For example, we can specify all the supported ABIs in the Application.mk file, and the ndk-build will generate native shared libraries to target all architectures.
The screenshot above shows the successful compile of native code for x86, and also shows shared library being generated and installed. We are now ready to rebuild our Android App, and install/run on x86 emulator or target device.
5. Rebuilding, Installing and Running the Android NDK App for IA
We can use “ant debug clean” to clear our old build files, and issue “ant debug” again to start off full rebuild of android project. Use “adb” to reinstall the app on target device or x86 emulator as shown in the screenshot below.
The screenshot below shows the App icon inside the x86 emulator, and the result of running the app inside the x86 emulator.
We have successfully built NDK based android app start to finish.
Using x86 NDK toolset to port existing NDK Apps to IA based devices
Android Apps with native code typically have a standard project structure, with “jni” folder containing the native sources, and the corresponding Android.mk/Application.mk build files. In the previous section, we saw a simple example with native source code and corresponding Android.mk file.
Android NDK toolset lets us specify all the target ABIs in Application.mk at once, and automatically generates native shared libraries for all targets. The android build system will automatically package all the target native libraries inside the APK, and at install time the Android package manager will install only the appropriate native library based on the target architecture.
We can invoke “ndk-build” or specify in Application.mk
APP_ABI := all
OR
APP_ABI := armeabi armeabi-v7a x86
Please refer http://developer.android.com/sdk/ndk/index.html for more information.
To port an existing Android App with native code, which currently does not target x86, the process of modifying the App to support IA is straightforward for most cases (as discussed above) – Unless the app uses architecture specific assembly language or constructs. There may be other issues like memory alignment or platform specific instructions usage. Please refer /en-us/articles/ndk-android-application-porting-methodologies for more details.
Summary
This article discussed creating and porting NDK based Android Apps to target IA. We walked-through step-by-step process to demonstrate the process of creating the NDK based App to use IA start-to-finish. We also discussed simple process made available by NDK toolset to port existing NDK based Android Apps to target IA as well.
For more information, visit http://software.intel.com/android
Promotional Feature