Getting started with the NDK

27
Fullstack as a service Getting Started with the NDK Native Development Kit (NDK) Kirill Kounik

Transcript of Getting started with the NDK

Page 1: Getting started with the NDK

Fullstack as a service

Getting Started with the NDKNative Development Kit (NDK)

Kirill Kounik

Page 2: Getting started with the NDK

Agenda

Introduction: What/Why NDKABIs - Architectures and CPUsNDK and Project setupLibrariesDebugging

Page 3: Getting started with the NDK

Native Development for Android

Natural/native language of Android development is Java

Android runs Linux kernel at its core

C/C++ development is possible, actually an Android application can be written entirely in C or C++

Leverages standard Java Native Interface (JNI)

However it will not benefit most apps

Page 4: Getting started with the NDK
Page 5: Getting started with the NDK

Benefits of Native Development for Android

• Mostly useful for computation intensive apps where performance becomes an issue

• May help to port or share code with other platforms, like iOS

• Use external native libraries

• Sometimes allows access to APIs not exposed in Java layer

Page 6: Getting started with the NDK

NDK development Cons:

Requires compilation for every CPU architecture and, possibly, a separate APK for each architecture.

May significantly increase APK size

JNI development is cumbersome for Java developers

Page 7: Getting started with the NDK

Native Development Kit or NDK for Android

NDK is a set of tools or toolchain used for for native development for Android platform.

http://developer.android.com/ndk/index.html

Samples*

https://github.com/googlesamples/android-ndk

Page 8: Getting started with the NDK

NDK and project setup

Page 9: Getting started with the NDK

NDK setup

NDK setup is very straight-forward:

Have standard Android development environment configures

Download and unzip NDK into a convenient location

Optionally get the samples from Github, they are not included in the NDK https://github.com/googlesamples/android-ndk *

* For samples for ndk-build use android-mk branch https://github.com/googlesamples/android-ndk/tree/android-mk

Page 10: Getting started with the NDK

ABI is Application Binary Interface

Different Android handsets use different CPUs, which in turn support different instruction sets. Each combination of CPU and instruction sets has its own Application Binary Interface, or ABI.

armeabiarmeabi-v7aarm64-v8ax86x86_64mipsmips64

Page 11: Getting started with the NDK

Project structure

Starting from version 1.3 Android Studio supports NDK development with the relatively new 'com.android.model.application' gradle plugin

.C, .CPP files under jni folder at the same level as java

*Old toolchain based on makefiles and ndk-build is not covered by this training.

Page 12: Getting started with the NDK

Project structure

Build settings defined in android.ndk section of the build.gradle file, for example

model {...

android.ndk {moduleName = "native-codec-jni"cppFlags.add("-UNDEBUG")// for native multimedialdLibs.addAll(["OpenMAXAL", "mediandk"])// for loggingldLibs.add("log")// for native windowsldLibs.add("android")stl = "stlport_static"

}...

}

Page 13: Getting started with the NDK

Everything you can configure in android.ndk

android.ndk {

// All configurations that can be changed in android.ndk.moduleName = "mymodule"ldLibs.addAll(['log', 'android'])ldLibs.add("log")ldFlags.add("-L/custom/lib/path")

...}

Page 14: Getting started with the NDK

Everything you can configure in android.ndk 2

android.ndk {

// All configurations that can be changed in android.ndk....

abiFilters.add("x86") // List of target ABIsCFlags.add("-DCUSTOM_DEFINE")cppFlags.add("-DCUSTOM_DEFINE")debuggable = falserenderscriptNdkMode = falsestl = "stlport_static" // choice of c++ runtimes providedplatformVersion = 15

}

● http://tools.android.com/tech-docs/new-build-system/gradle-experimental#TOC-Ndk-Integration

Page 15: Getting started with the NDK

C++ runtimes (stl = "stlport_static")

the build system automatically links the standard C libraries, real-time extensions, and pthread

By default NDK provides a very minimal standard C++ runtime support library (libstdc++). This minimal support does not include, for example:

○ Standard C++ Library support (except a few trivial headers).

○ C++ exceptions support○ RTTI support

Available runtimes: GAbi++, STLport, GNU STL, LLVM libc++

Detailed information about various available runtimes and supplied headers can be found in the docs: developer.android.com/ndk/guides/cpp-support.html

Page 16: Getting started with the NDK

Resulting fat APK structure$ unzip -l build/outputs/apk/app-all-debug.apkArchive: build/outputs/apk/app-all-debug.apk

Length Date Time Name--------- ---------- ----- ----

1896 03-31-2016 14:10 AndroidManifest.xml...

2724 03-31-2016 14:10 classes.dex5592 03-31-2016 14:10 lib/arm64-v8a/libhello-jni.so13552 03-31-2016 14:10 lib/armeabi/libhello-jni.so13560 03-31-2016 14:10 lib/armeabi-v7a/libhello-jni.so5460 03-31-2016 14:10 lib/mips/libhello-jni.so6048 03-31-2016 14:10 lib/mips64/libhello-jni.so5264 03-31-2016 14:10 lib/x86/libhello-jni.so5784 03-31-2016 14:10 lib/x86_64/libhello-jni.so

...--------- -------

81286 17 files

Page 17: Getting started with the NDK

Split APKs

In native code causes an APK too large. To build separate APK for each architecture

android {...splits {

abi {enable truereset()include 'x86', 'armeabi-v7a', 'mips' // ABIs to includeuniversalApk true // build “fat” version

}}

}

Page 18: Getting started with the NDK

Split APKs - version code support

Every APK in Play store must have unique versionCode

// map for the version codeproject.ext.versionCodes = ['armeabi-v7a':1, 'x86':2, 'mips' : 3]

applicationVariants.all { variant ->// assign different version code for each outputvariant.outputs.each { output ->

output.versionCodeOverride =project.ext.versionCodes.get(output.getFilter(OutputFile.ABI)) * 10000

+ variant.versionCode}

}

* http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits

Page 19: Getting started with the NDK

Stable NDK libraries (ldLibs.addAll(['log', 'android']))

The Android NDK provides a set of native headers for prebuilt libraries that allow access various system features without the need to go through JNI.

Library Description Header files

log Android log support log.h

z ZLib compression library zlib.h, zconf.h

dl Dynamic linker library dlfcn.h

GLESv1_CM, GLESv2, OpenSLES, EGL, GLESv3, 3.1

Open GL ES, EGL, libraries for various versions many

android For writing pure native apps many

OpenMAXAL Android native multimedia handling is based on Khronos Group OpenMAX AL

OMXAL/OpenMAXAL.h, OMXAL/OpenMAXAL_Platform.h, OpenMAXAL_Android.h

jnigraphics Native interface to the pixel buffers of bitmaps bitmap.h

Page 20: Getting started with the NDK

Pure Native Activity

android.app.NativeActivity is a glue between Android and and pure native Activity

No need to subclass it, only properly define in the manifest

Android framework APIs can be accessed through the JNI

Native code should adhere to certain structure defined by NDK in native_activity.h

Alternatively use helper library defined in android_native_app_glue.h

Implement native function ANativeActivity_onCreate

Implement ANativeActivity->callbacks to manage activity lifecycle

Page 21: Getting started with the NDK

Pure native activity manifest

<application android:label="@string/app_name" android:hasCode="false">

<!-- Our activity is the built-in NativeActivity framework class.This will take care of integrating with our NDK code. -->

<activity android:name="android.app.NativeActivity"android:label="@string/app_name"android:configChanges="orientation|keyboardHidden">

<!-- Tell NativeActivity the name of or .so --><meta-data android:name="android.app.lib_name"

android:value="native-activity" />...

</activity></application>

● Sample: https://github.com/googlesamples/android-ndk/tree/master/native-activity

Page 22: Getting started with the NDK

Debugging JNI code

In the latest releases of Android Studio native debugger is nicely integrated and can be used out of the box

Page 23: Getting started with the NDK
Page 24: Getting started with the NDK

Debugging JNI crashes

Tombstone files are crash dumps with some extra information

Up to 10 last tombstone files saved by the system and replaced cyclically

$ adb shell ls /data/tombstones

$ adb pull /data/tombstones/tombstone_00

Page 25: Getting started with the NDK

Examining tombstone files with ndk-stack

Identify crash address in your library

$ ndk-stack -sym <root symbols dir> [-dump <dump file>]

$ ndk-stack -sym .\app\build\intermediates\symbols -dump .\tombstone_00

Page 26: Getting started with the NDK

Finding file location with addr2line

addr2line command that you need to use depends on the ABI of your crashed file.

alias addr2line= \

’$NDK/toolchains/x86_64-4.9/prebuilt/windows/bin/i686-linux-android-addr2line.exe’

Find the crashed line

$ addr2line -f -e <input file> <address>

Page 27: Getting started with the NDK

Summary

JNIEnv*, Local/global refs, method signatures, javah, javap, tombstones, ndk-stack, addr2line