289 lines
11 KiB
Plaintext
289 lines
11 KiB
Plaintext
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 explicitely load the library. For example, to load
|
|
it at application startup, 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.
|
|
|
|
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 explicitely 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/ 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 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 Android 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 whether 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.
|
|
|
|
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.
|