| 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 Java source code to call methods |
| implemented in native code through the Java Native Interface (JNI). In a |
| nutshell, this means that: |
| |
| - Your application's Java 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 explicitely load the library. For example, to load |
| it at application startup, simply add the following to its Java 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. |
| |
| 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 |
| 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 "Java 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 explicitely supported by the NDK |
| headers, then applications should not depend on it being available, or |
| they risk breaking after the next off-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/ Run build/host-setup.sh to configure the NDK |
| |
| 2/ Place your sources under sources/<mysrc>/... |
| |
| 3/ Write sources/<mysrc>/Android.mk to describe your sources |
| to the NDK build system |
| |
| 4/ Write apps/<myapp>/Application.mk to describe your application |
| and the native sources it needs to the NDK build system |
| |
| 5/ Build your native code by running "make APP=<myapp>" |
| in the top-level NDK directory. |
| |
| 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: |
| - - - - - - - - - - - - - - |
| |
| After installing the NDK as described in docs/INSTALL.TXT, you should call |
| the 'build/host-setup.sh' script to configure your NDK. |
| |
| This script is used to probe your host system and verify a few pre-requisites. |
| It will then generate a configuration file (e.g. out/host/config-host.mk) that |
| is later used during NDK builds. |
| |
| In some cases, this might instruct you to download an archive containing |
| prebuilt toolchain binaries for your development platform, the unzip it |
| to the NDK root directory. The message should contain enough information |
| to let you do that. |
| |
| If you forget this step, trying to build with the NDK will generate an |
| error message telling you what to do. |
| |
| |
| III.2/ Placing C and C++ sources: |
| - - - - - - - - - - - - - - - - - |
| |
| The NDK build system expects your sources to be visible under the top-level |
| 'sources' directory. You should first create a directory like: |
| |
| $NDK/sources/<mysrc>/ |
| |
| You are pretty free to organize the content of 'sources' 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 Java application |
| package names. |
| |
| For the record, the NDK comes with a 'sources/samples' directory which |
| itself contains several subdirectories for various sample modules. |
| |
| 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.TXT for details). |
| |
| It is possible to store your sources in a different location, as long as |
| you create $NDK/sources/<mysrc> as a symbolic link. For proper operation, the |
| NDK build system must be able to 'see' your source files and build scripts |
| from $NDK/sources. |
| |
| |
| 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. Their syntax is described in details in |
| the file docs/ANDROID-MK.TXT. |
| |
| 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. |
| |
| All Android.mk files are parsed by the build system before any build occurs. |
| Note also 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 all files that match the following: |
| |
| $NDK/sources/*/Android.mk |
| |
| If you want to define Android.mk files in sub-directories, you should |
| include them explicitely 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: |
| - - - - - - - - - - - - - - - - - - - - - - - |
| |
| While an Android.mk file describes your modules to the build system, you |
| need to write an Application.mk file to describe your application and the |
| modules it requires. This file must be located in: |
| |
| $NDK/apps/<myapp>/Application.mk |
| |
| Where <myapp> is a short descriptive name for your application that will |
| be used to invoke the NDK build (and not go into final APKs). The file is |
| used to provide the following to the NDK build: |
| |
| - The location of your Java application's project path |
| |
| - The list of NDK modules that is required by your application. |
| This should really be a list of 'shared library' modules. |
| |
| - Optional information, like wether you want a release or debug |
| build, specific C or C++ compiler flags and others. |
| |
| - Planned: the list of specific platforms/CPUs you want to explicitely |
| target (currently only one is supported). |
| |
| The syntax of an Application.mk file is very simple and is described in |
| docs/APPLICATION-MK.TXT |
| |
| You can define several Application.mk corresponding to different builds |
| of the same application, for example: |
| |
| $NDK/apps/release/Application.mk |
| $NDK/apps/debug/Application.mk |
| |
| |
| III.5/ Invoke the NDK build system: |
| - - - - - - - - - - - - - - - - - - |
| |
| On the command-line, go to the top-level NDK directory, then invoke the |
| build system with: |
| |
| make APP=<myapp> |
| |
| Where 'make' refers to GNU Make, and <myapp> is the name of one of the |
| subdirectories of '$NDK/apps/' |
| |
| This will try to build all modules with relevant options, the final |
| shared libraries listed by your Application.mk and, in case of success, |
| will copy stripped versions of the shared libraries 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). |
| |
| |
| |
| IV. Debugging support: |
| - - - - - - - - - - - - |
| |
| Debugging your native code with this initial release of the NDK is still |
| very rough. |
| |
| XXX: Describe the hairy steps currently required to debug native code here |
| |
| Note that we plan to make this much easier in a later NDK release, all of |
| this without changing your sources, Android.mk and Application.mk files. |
| |
| |
| V. Profiling support: |
| - - - - - - - - - - - |
| |
| XXX: Should work in theory, doesn't work in practice, need to debug this... |
| |