| <html><body><pre>Android NDK Overview |
| |
| Introduction: |
| |
| The Android NDK is a set of tools that allows Android application developers |
| to embed native machine code compiled from C and/or C++ source files into |
| their application packages. |
| |
| IMPORTANT: |
| The Android NDK can only be used to target Android system images |
| running Cupcake (a.k.a 1.5) or later versions of the platform. |
| |
| 1.0 and 1.1 system images are specifically *not* supported due to |
| subtle ABI and toolchain changes that happened for the 1.5 release. |
| |
| |
| I. Android NDK Goals: |
| --------------------- |
| |
| The Android VM allows your application's source code to call methods |
| implemented in native code through the JNI. In a nutshell, this means that: |
| |
| - Your application's source code will declare one or more methods |
| with the 'native' keyword to indicate that they are implemented through |
| native code. E.g.: |
| |
| native byte[] loadFile(String filePath); |
| |
| - You must provide a native shared library that contains the |
| implementation of these methods, which will be packaged into your |
| application's .apk. This library must be named according to standard |
| Unix conventions as lib<something>.so, and shall contain a standard JNI |
| entry point (more on this later). For example: |
| |
| libFileLoader.so |
| |
| - Your application must explicitly load the library. For example, to load |
| it at application start-up, simply add the following to its source code: |
| |
| static { |
| System.loadLibrary("FileLoader"); |
| } |
| |
| Note that you should not use the 'lib' prefix and '.so' suffix here. |
| |
| |
| The Android NDK is a complement to the Android SDK that helps you to: |
| |
| - Generate JNI-compatible shared libraries that can run on the Android |
| 1.5 platform (and later) running on ARM CPUs. |
| |
| - Copy the generated shared libraries to a proper location of your |
| application project path, so they will be automatically added to your |
| final (and signed) .apks |
| |
| - In later revisions of the NDK, we intend to provide tools that help |
| debug your native code through a remote gdb connection and as much |
| source/symbol information as possible. |
| |
| Moreover, the Android NDK provides: |
| |
| - A set of cross-toolchains (compilers, linkers, etc..) that can |
| generate native ARM binaries on Linux, OS X and Windows (with Cygwin) |
| |
| - A set of system headers corresponding to the list of stable native APIs |
| supported by the Android platform. This corresponds to definitions that |
| are guaranteed to be supported in all later releases of the platform. |
| |
| They are documented in the file docs/STABLE-APIS.html |
| |
| IMPORTANT: |
| Keep in mind that most of the native system libraries in Android system |
| images are not frozen and might changed drastically, or even deleted, |
| in later updates and releases of the platform. |
| |
| - A build system that allow developers to only write very short build files |
| to describe which sources need to be compiled, and how. The build system |
| deals with all the hairy toolchain/platform/CPU/ABI specifics. Moreover, |
| later updates of the NDK can add support for more toolchains, platforms, |
| system interfaces without requiring changes in the developer's build |
| files (more on this later). |
| |
| |
| II. Android NDK Non-Goals: |
| -------------------------- |
| |
| The NDK is *not* a good way to write generic native code that runs on Android |
| devices. In particular, your applications should still be written in the Java |
| programming language, handle Android system events appropriately to avoid the |
| "Application Not Responding" dialog or deal with the Android application |
| life-cycle. |
| |
| Note however that is is possible to write a sophisticated application in |
| native code with a small "application wrapper" used to start/stop it |
| appropriately. |
| |
| A good understanding of JNI is highly recommended, since many operations |
| in this environment require specific actions from the developers, that are |
| not necessarily common in typical native code. These include: |
| |
| - Not being able to directly access the content of VM objects through |
| direct native pointers. E.g. you cannot safely get a pointer to a |
| String object's 16-bit char array to iterate over it in a loop. |
| |
| - Requiring explicit reference management when the native code wants to |
| keep handles to VM objects between JNI calls. |
| |
| |
| The NDK only provides system headers for a very limited set of native |
| APIs and libraries supported by the Android platform. While a typical |
| Android system image includes many native shared libraries, these should |
| be considered an implementation detail that might change drastically between |
| updates and releases of the platform. |
| |
| If an Android system library is not explicitly supported by the NDK |
| headers, then applications should not depend on it being available, or |
| they risk breaking after the next over-the-air system update on various |
| devices. |
| |
| Selected system libraries will gradually be added to the set of stable NDK |
| APIs. |
| |
| |
| III. NDK development in practice: |
| --------------------------------- |
| |
| Here's a very rough overview of how you can develop native code with the |
| Android NDK: |
| |
| 1/ Place your native sources under $PROJECT/jni/... |
| |
| 2/ Write $PROJECT/jni/Android.mk to describe your sources |
| to the NDK build system |
| |
| 3/ Optional: write $PROJECT/jni/Application.mk to describe your |
| project in more details to the build system. You don't need |
| one to get started though, but this allows you to target |
| more than one CPU or override compiler/linker flags |
| (see docs/APPLICATION-MK.html for all details). |
| |
| 4/ Build your native code by running "$NDK/ndk-build" from your |
| project directory, or any of its sub-directories. |
| |
| The last step will copy, in case of success, the stripped shared libraries |
| your application needs to your application's root project directory. You |
| will then need to generate your final .apk through the usual means. |
| |
| Now, for a few more details: |
| |
| |
| III.1/ Configuring the NDK: |
| - - - - - - - - - - - - - - |
| |
| Previous releases required that you run the 'build/host-setup.sh' |
| script to configure your NDK. This step has been removed completely |
| in release 4 (a.k.a. NDK r4). |
| |
| |
| III.2/ Placing C and C++ sources: |
| - - - - - - - - - - - - - - - - - |
| |
| Place your native sources under the following directory: |
| |
| $PROJECT/jni/ |
| |
| Where $PROJECT corresponds to the path of your Android application |
| project. |
| |
| You are pretty free to organize the content of 'jni' as you want, |
| the directory names and structure here will not influence the final |
| generated application packages, so you don't have to use pseudo-unique |
| names like com.<mycompany>.<myproject> as is the case for application |
| package names. |
| |
| Note that C and C++ sources are supported. The default C++ file extensions |
| supported by the NDK is '.cpp', but other extensions can be handled as well |
| (see docs/ANDROID-MK.html for details). |
| |
| It is possible to store your sources in a different location by adjusting |
| your Android.mk file (see below). |
| |
| |
| III.3/ Writing an Android.mk build script: |
| - - - - - - - - - - - - - - - - - - - - - - |
| |
| An Android.mk file is a small build script that you write to describe your |
| sources to the NDK build system. Its syntax is described in details in |
| the file docs/ANDROID-MK.html. |
| |
| In a nutshell, the NDK groups your sources into "modules", where each module |
| can be one of the following: |
| |
| - a static library |
| - a shared library |
| |
| You can define several modules in a single Android.mk, or you can write |
| several Android.mk files, each one defining a single module. |
| |
| Note that a single Android.mk might be parsed several times by the build |
| system so don't assume that certain variables are not defined in them. |
| By default, the NDK will look for the following build script: |
| |
| $PROJECT/jni/Android.mk |
| |
| If you want to define Android.mk files in sub-directories, you should |
| include them explicitly in your top-level Android.mk. There is even |
| a helper function to do that, i.e. use: |
| |
| include $(call all-subdir-makefiles) |
| |
| This will include all Android.mk files in sub-directories of the current |
| build file's path. |
| |
| |
| III.4/ Writing an Application.mk build file (optional): |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| |
| While an Android.mk file describes your modules to the build system, the |
| Application.mk file describes your application itself. See the |
| docs/APPLICATION-MK.html document to understand what this file allows you |
| to do. This includes, among others: |
| |
| - The exact list of modules required by your application. |
| |
| - The CPU architecture(s) to generate machine code for. |
| |
| - Optional information, like whether you want a release or debug |
| build, specific C or C++ compiler flags and others that should |
| apply to all modules being built. |
| |
| This file is optional: by default the NDK will provide one that simply |
| builds *all* the modules listed from your Android.mk (and all the makefiles |
| it includes) and target the default CPU ABI (armeabi). |
| |
| There are two ways to use an Application.mk: |
| |
| - Place it under $PROJECT/jni/Application.mk, and it will be picked |
| up automatically by the 'ndk-build' script (more on this later) |
| |
| - Place it under $NDK/apps/<name>/Application.mk, where $NDK |
| points to your NDK installation path. After that, launch |
| "make APP=<name>" from the NDK directory. |
| |
| This was the way this file was used before Android NDK r4. |
| It is still supported for compatibility reasons, but we strongly |
| encourage you to use the first method instead, since it is much |
| simpler and doesn't need modifying / changing directories of the |
| NDK installation tree. |
| |
| Again, see docs/APPLICATION-MK.html for a complete description of its |
| content. |
| |
| |
| III.5/ Invoke the NDK build system: |
| - - - - - - - - - - - - - - - - - - |
| |
| The preferred way to build machine code with the NDK is to use the |
| 'ndk-build' script introduced with Android NDK r4. You can also use |
| a second, legacy, method that depends on creating a '$NDK/apps' subdirectory. |
| |
| In both cases, a successful build will copy the final stripped binary modules |
| (i.e. shared libraries) required by your application to your application's |
| project path (Note that unstripped versions are kept for debugging |
| purposes, there is no need to copy unstripped binaries to a device). |
| |
| |
| 1: Using the 'ndk-build' command: |
| --------------------------------- |
| |
| The 'ndk-build' script, located at the top of the NDK installation path |
| can be invoked directly from your application project directory (i.e. the |
| one where your AndroidManifest.xml is located) or any of its sub-directories. |
| For example: |
| |
| cd $PROJECT |
| $NDK/ndk-build |
| |
| This will launch the NDK build scripts, which will automatically probe your |
| development system and application project file to determine what to build. |
| |
| For example: |
| |
| ndk-build |
| ndk-build clean --> clean generated binaries |
| ndk-build -B V=1 --> force complete rebuild, showing commands |
| |
| By default, it expects an optional file under $PROJECT/jni/Application.mk, |
| and a required $PROJECT/jni/Android.mk. |
| |
| On success, this will copy the generated binary modules (i.e. shared |
| libraries) to the appropriate location in your project tree. You can later |
| rebuild the full Android application package either through the usual |
| 'ant' command, or the ADT Eclipse plug-in. |
| |
| See docs/NDK-BUILD.html for a more complete description of what this script |
| does and which options it can take. |
| |
| |
| III.6/ Specifying custom output directories: |
| - - - - - - - - - - - - - - - - - - - - - - - |
| |
| By default, ndk-build places all intermediate generated files under |
| $PROJECT/obj. You can however select a different location by defining |
| the NDK_OUT environment variable to point to a different directory. |
| |
| When defined, this variable has two effects: |
| |
| 1/ It ensures that all files that normally go under $PROJECT/obj are |
| stored in $NDK_OUT instead |
| |
| 2/ It tells ndk-gdb to look into $NDK_OUT, instead of $PROJECT/obj for |
| any symbolized (i.e. unstripped) versions of the generated binaries. |
| |
| |
| IV. Rebuild your application package: |
| - - - - - - - - - - - - - - - - - - - |
| |
| After generating the binaries with the NDK, you need to rebuild your |
| Android application package files (.apk) using the normal means, i.e. |
| either using the 'ant' command or the ADT Eclipse plug-in. |
| |
| See the Android SDK documentation for more details. The new .apk will |
| embed your shared libraries, and they will be extracted automatically |
| at installation time by the system when you install the package on a |
| target device. |
| |
| |
| V. Debugging support: |
| - - - - - - - - - - - |
| |
| The NDK provides a helper script, named 'ndk-gdb' to very easily launch |
| a native debugging session of your applications. |
| |
| Native debugging can *ONLY* be performed on production devices running |
| Android 2.2 or higher, and does not require root or privileged access, as |
| long as your application is debuggable. |
| |
| For more information, read docs/NDK-GDB.html. In a nutshell, native debugging |
| follows this simple scheme: |
| |
| 1. Ensure your application is debuggable (e.g. set android:debuggable |
| to "true" in your AndroidManifest.xml) |
| |
| 2. Build your application with 'ndk-build', then install it on your |
| device/emulator. |
| |
| 3. Launch your application. |
| |
| 4. Run 'ndk-gdb' from your application project directory. |
| |
| You will get a gdb prompt. See the GDB User Manual for a list of useful |
| commands. |
| </pre></body></html> |