1 Android NDK Overview 2 === 3 4 Introduction: 5 --- 6 7 The Android NDK is a set of tools that allows Android application developers 8 to embed native machine code compiled from C and/or C++ source files into 9 their application packages. 10 11 IMPORTANT: 12 > The Android NDK can only be used to target Android system images 13 running Cupcake (a.k.a 1.5) or later versions of the platform. 14 15 > 1.0 and 1.1 system images are specifically *not* supported due to 16 subtle ABI and toolchain changes that happened for the 1.5 release. 17 18 19 I. Android NDK Goals: 20 --------------------- 21 22 The Android VM allows your application's source code to call methods 23 implemented in native code through the JNI. In a nutshell, this means that: 24 25 - Your application's source code will declare one or more methods 26 with the 'native' keyword to indicate that they are implemented through 27 native code. E.g.: 28 29 native byte[] loadFile(String filePath); 30 31 - You must provide a native shared library that contains the 32 implementation of these methods, which will be packaged into your 33 application's .apk. This library must be named according to standard 34 Unix conventions as lib<something>.so, and shall contain a standard JNI 35 entry point (more on this later). For example: 36 37 libFileLoader.so 38 39 - Your application must explicitly load the library. For example, to load 40 it at application start-up, simply add the following to its source code: 41 42 static { 43 System.loadLibrary("FileLoader"); 44 } 45 46 Note that you should not use the 'lib' prefix and '.so' suffix here. 47 48 49 The Android NDK is a complement to the Android SDK that helps you to: 50 51 - Generate JNI-compatible shared libraries that can run on the Android 52 1.5 platform (and later) running on ARM CPUs. 53 54 - Copy the generated shared libraries to a proper location of your 55 application project path, so they will be automatically added to your 56 final (and signed) .apks 57 58 - In later revisions of the NDK, we intend to provide tools that help 59 debug your native code through a remote gdb connection and as much 60 source/symbol information as possible. 61 62 Moreover, the Android NDK provides: 63 64 - A set of cross-toolchains (compilers, linkers, etc..) that can 65 generate native ARM binaries on Linux, OS X and Windows (with Cygwin) 66 67 - A set of system headers corresponding to the list of stable native APIs 68 supported by the Android platform. This corresponds to definitions that 69 are guaranteed to be supported in all later releases of the platform. 70 71 They are documented in the file docs/STABLE-APIS.html 72 73 IMPORTANT: 74 Keep in mind that most of the native system libraries in Android system 75 images are not frozen and might changed drastically, or even deleted, 76 in later updates and releases of the platform. 77 78 - A build system that allow developers to only write very short build files 79 to describe which sources need to be compiled, and how. The build system 80 deals with all the hairy toolchain/platform/CPU/ABI specifics. Moreover, 81 later updates of the NDK can add support for more toolchains, platforms, 82 system interfaces without requiring changes in the developer's build 83 files (more on this later). 84 85 86 II. Android NDK Non-Goals: 87 -------------------------- 88 89 The NDK is *not* a good way to write generic native code that runs on Android 90 devices. In particular, your applications should still be written in the Java 91 programming language, handle Android system events appropriately to avoid the 92 "Application Not Responding" dialog or deal with the Android application 93 life-cycle. 94 95 Note however that is is possible to write a sophisticated application in 96 native code with a small "application wrapper" used to start/stop it 97 appropriately. 98 99 A good understanding of JNI is highly recommended, since many operations 100 in this environment require specific actions from the developers, that are 101 not necessarily common in typical native code. These include: 102 103 - Not being able to directly access the content of VM objects through 104 direct native pointers. E.g. you cannot safely get a pointer to a 105 String object's 16-bit char array to iterate over it in a loop. 106 107 - Requiring explicit reference management when the native code wants to 108 keep handles to VM objects between JNI calls. 109 110 111 The NDK only provides system headers for a very limited set of native 112 APIs and libraries supported by the Android platform. While a typical 113 Android system image includes many native shared libraries, these should 114 be considered an implementation detail that might change drastically between 115 updates and releases of the platform. 116 117 If an Android system library is not explicitly supported by the NDK 118 headers, then applications should not depend on it being available, or 119 they risk breaking after the next over-the-air system update on various 120 devices. 121 122 Selected system libraries will gradually be added to the set of stable NDK 123 APIs. 124 125 126 III. NDK development in practice: 127 --------------------------------- 128 129 Here's a very rough overview of how you can develop native code with the 130 Android NDK: 131 132 1. Place your native sources under `$PROJECT/jni/`... 133 134 2. Write `$PROJECT/jni/Android.mk` to describe your sources 135 to the NDK build system 136 137 3. Optional: write `$PROJECT/jni/Application.mk` to describe your 138 project in more details to the build system. You don't need 139 one to get started though, but this allows you to target 140 more than one CPU or override compiler/linker flags 141 (see `docs/APPLICATION-MK.html` for all details). 142 143 4. Build your native code by running "`$NDK/ndk-build`" from your 144 project directory, or any of its sub-directories. 145 146 The last step will copy, in case of success, the stripped shared libraries 147 your application needs to your application's root project directory. You 148 will then need to generate your final .apk through the usual means. 149 150 Now, for a few more details: 151 152 153 ### III.1/ Configuring the NDK: 154 155 156 Previous releases required that you run the 'build/host-setup.sh' 157 script to configure your NDK. This step has been removed completely 158 in release 4 (a.k.a. NDK r4). 159 160 161 ### III.2/ Placing C and C++ sources: 162 163 Place your native sources under the following directory: 164 165 $PROJECT/jni/ 166 167 Where `$PROJECT` corresponds to the path of your Android application 168 project. 169 170 You are pretty free to organize the content of 'jni' as you want, 171 the directory names and structure here will not influence the final 172 generated application packages, so you don't have to use pseudo-unique 173 names like `com.<mycompany>.<myproject>` as is the case for application 174 package names. 175 176 Note that C and C++ sources are supported. The default C++ file extensions 177 supported by the NDK is '.cpp', but other extensions can be handled as well 178 (see docs/ANDROID-MK.html for details). 179 180 It is possible to store your sources in a different location by adjusting 181 your Android.mk file (see below). 182 183 184 ### III.3/ Writing an Android.mk build script: 185 186 An Android.mk file is a small build script that you write to describe your 187 sources to the NDK build system. Its syntax is described in details in 188 the file docs/ANDROID-MK.html. 189 190 In a nutshell, the NDK groups your sources into "modules", where each module 191 can be one of the following: 192 193 - a static library 194 - a shared library 195 196 You can define several modules in a single Android.mk, or you can write 197 several Android.mk files, each one defining a single module. 198 199 Note that a single Android.mk might be parsed several times by the build 200 system so don't assume that certain variables are not defined in them. 201 By default, the NDK will look for the following build script: 202 203 $PROJECT/jni/Android.mk 204 205 If you want to define Android.mk files in sub-directories, you should 206 include them explicitly in your top-level Android.mk. There is even 207 a helper function to do that, i.e. use: 208 209 include $(call all-subdir-makefiles) 210 211 This will include all Android.mk files in sub-directories of the current 212 build file's path. 213 214 215 ### III.4/ Writing an Application.mk build file (optional): 216 217 While an Android.mk file describes your modules to the build system, the 218 Application.mk file describes your application itself. See the 219 docs/APPLICATION-MK.html document to understand what this file allows you 220 to do. This includes, among others: 221 222 - The exact list of modules required by your application. 223 224 - The CPU architecture(s) to generate machine code for. 225 226 - Optional information, like whether you want a release or debug 227 build, specific C or C++ compiler flags and others that should 228 apply to all modules being built. 229 230 This file is optional: by default the NDK will provide one that simply 231 builds *all* the modules listed from your Android.mk (and all the makefiles 232 it includes) and target the default CPU ABI (armeabi). 233 234 There are two ways to use an Application.mk: 235 236 - Place it under `$PROJECT/jni/Application.mk`, and it will be picked 237 up automatically by the 'ndk-build' script (more on this later) 238 239 - Place it under `$NDK/apps/<name>/Application.mk`, where $NDK 240 points to your NDK installation path. After that, launch 241 "`make APP=<name>`" from the NDK directory. 242 243 This was the way this file was used before Android NDK r4. 244 It is still supported for compatibility reasons, but we strongly 245 encourage you to use the first method instead, since it is much 246 simpler and doesn't need modifying / changing directories of the 247 NDK installation tree. 248 249 Again, see docs/APPLICATION-MK.html for a complete description of its 250 content. 251 252 253 ### III.5/ Invoke the NDK build system: 254 255 The preferred way to build machine code with the NDK is to use the 256 'ndk-build' script introduced with Android NDK r4. You can also use 257 a second, legacy, method that depends on creating a '$NDK/apps' subdirectory. 258 259 In both cases, a successful build will copy the final stripped binary modules 260 (i.e. shared libraries) required by your application to your application's 261 project path (Note that unstripped versions are kept for debugging 262 purposes, there is no need to copy unstripped binaries to a device). 263 264 265 ### 1: Using the 'ndk-build' command: 266 267 The 'ndk-build' script, located at the top of the NDK installation path 268 can be invoked directly from your application project directory (i.e. the 269 one where your AndroidManifest.xml is located) or any of its sub-directories. 270 For example: 271 272 cd $PROJECT 273 $NDK/ndk-build 274 275 This will launch the NDK build scripts, which will automatically probe your 276 development system and application project file to determine what to build. 277 278 For example: 279 280 ndk-build 281 ndk-build clean --> clean generated binaries 282 ndk-build -B V=1 --> force complete rebuild, showing commands 283 284 By default, it expects an optional file under $PROJECT/jni/Application.mk, 285 and a required $PROJECT/jni/Android.mk. 286 287 On success, this will copy the generated binary modules (i.e. shared 288 libraries) to the appropriate location in your project tree. You can later 289 rebuild the full Android application package either through the usual 290 'ant' command, or the ADT Eclipse plug-in. 291 292 See docs/NDK-BUILD.html for a more complete description of what this script 293 does and which options it can take. 294 295 296 ### III.6/ Specifying custom output directories: 297 298 By default, ndk-build places all intermediate generated files under 299 $PROJECT/obj. You can however select a different location by defining 300 the NDK_OUT environment variable to point to a different directory. 301 302 When defined, this variable has two effects: 303 304 1. It ensures that all files that normally go under $PROJECT/obj are 305 stored in $NDK_OUT instead 306 307 2. It tells ndk-gdb to look into $NDK_OUT, instead of $PROJECT/obj for 308 any symbolized (i.e. unstripped) versions of the generated binaries. 309 310 Similarly you can override the default $PROJECT/libs (for libraries and 311 gdbserver, etc) by defining NDK_LIBS_OUT to a new path. This is rarely 312 done since build system expects the default $PROJECT/libs/ 313 314 315 ### IV. Rebuild your application package: 316 317 After generating the binaries with the NDK, you need to rebuild your 318 Android application package files (.apk) using the normal means, i.e. 319 either using the 'ant' command or the ADT Eclipse plug-in. 320 321 See the Android SDK documentation for more details. The new .apk will 322 embed your shared libraries, and they will be extracted automatically 323 at installation time by the system when you install the package on a 324 target device. 325 326 327 ### V. Debugging support: 328 329 The NDK provides a helper script, named 'ndk-gdb' to very easily launch 330 a native debugging session of your applications. 331 332 Native debugging can *ONLY* be performed on production devices running 333 Android 2.2 or higher, and does not require root or privileged access, as 334 long as your application is debuggable. 335 336 For more information, read docs/NDK-GDB.html. In a nutshell, native debugging 337 follows this simple scheme: 338 339 1. Ensure your application is debuggable (e.g. set android:debuggable 340 to "true" in your AndroidManifest.xml) 341 342 2. Build your application with 'ndk-build', then install it on your 343 device/emulator. 344 345 3. Launch your application. 346 347 4. Run 'ndk-gdb' from your application project directory. 348 349 You will get a gdb prompt. See the GDB User Manual for a list of useful 350 commands. 351