native code in android applications
TRANSCRIPT
Native code in Android applications
My projects using NDK
YummLow memory overhead for image decoding
Hudriks Mathcocos2d-x; cross-platform: iOS and Android
Secure Video PlayerCritical DRM code; cross-platform code (iOS/Android/Linux/OS X/Windows);
high-performance
Overview
Android Runtime
Core Libraries (Java)
JVM (Dalvik)
LibrariesMediaSQLite OpenGLOpenSL ES
Linux Platform
/libs/armeabi/
Your Java Application
Java code
Android NDK
• Documentation
• Toolchain - ndk-build, gcc/clang, gdbserver, …
• NDK framework headers
• Build system
NDK frameworks• dl, zlib, math, log • OpenGL ES 1.x
android-4 (1.6)
• OpenGL ES 2.0
android-5 (2.0)
• JNI Graphics - java Bitmaps on low level
android-8 (2.2)
• EGL • OpenSL ES - audio library • Native Applications - native activity, etc
android-9 (2.3)
• OpenMAX
android-14 (4.0)
• OpenGL ES 3.0
android-18 (4.3)
Compilation process
compiler
source objects
.o.o.o.o.o.c/.c++ linker .so
shared library
static library
.o.o.o
.a (archive)
.so
Application structure
• jni/ (source code)
• Android.mk
• [Application.mk]
• module1/
• Android.mk
• libs/armeabi/libnative.so - compiled shared library
CPU specific
• Application Binary Interface (ABI): • armeabi - at least ARMv5TE • armeabi-v7a - Thumb-2; VFP hardware FPU; NEON • x86 • mips
• Application.mk: • APP_ABI := all • APP_ABI := armeabi armeabi-v7a
Java Native Interface
JNI in C and C++#include <jni.h>
struct JNINativeInterface { jclass (*FindClass)(JNIEnv*, const char*);}typedef const struct JNINativeInterface* JNIEnv;!JNIEnv* env;(*env)->FindClass(env, “classname”);
C
JNI in C and C++
struct _JNIEnv { jclass FindClass(const char* name) { return functions->FindClass(this, name); }}!JNIEnv* env;env->FindClass(“classname”);
C++
Mapping native functions
libnative.so- function_1()
- function_2()
- function_3()
- function_4()
- function_5()
Java.class- function_1()
- function_2()
- function_3()
- function_4()
- function_5()
Mapping native functions
public native static int testNative(int a, int b);
.java
jint Java_com_example_jnibasics_NativeDemo_testNative(JNIEnv *env, jclass obj, jint a, jint b)
.c
package name
> javah com.example.jnibasics.NativeDemo
javah
Mapping native functionsjint RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint nMethods);
typedef struct { char *name; char *signature; void *fnPtr; } JNINativeMethod;
jint addVals(JNIEnv *env, jclass obj, jint a, jint b) {…}
Mapping native functionsstatic JNINativeMethod sMethods[] = { {"testNative", "(II)I", (void*)addVals}};
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv *env = NULL; jclass klass; if((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) return -1;! ! return JNI_VERSION_1_6;}
klass = (*env)->FindClass(env, “com/example/jnibasics/NativeDemo”); (*env)->RegisterNatives(env, klass, gMethods, 1);
Loading .so from Java
static { System.loadLibrary("JNIBasics"); }
JNIBasics Dependency
static { System.loadLibrary("Dependency"); System.loadLibrary("JNIBasics"); }
Demo
References
jobject gObject = NULL;!void function(JNIEnv* jobject obj) { gObject = (*env)->NewGlobalRef(env, obj);}!void finish(JNIEnv* env) { (*env)->DeleteGlobalRef(env, gObject);}
Calling Java methods from native
jclass clz = (*env)->FindClass(env, “com/example/jnibasics/NativeDemo");!jmethodID method = (*env)->GetMethodID(env, clz, "methodName", “(II)Ljava/lang/String;");!jstring result = (*env)->CallObjectMethod(env, obj, method, 5, 6);
Accessing java strings
jstring jstr;const char* str;!str = (*env)->GetStringUTFChars(env, jstr, NULL);!...!(*env)->ReleaseStringUTFChars(env, jstr, str);
Further reading
• Attaching Java threads
• Creating new Java objects from native code
• Distinguish between virtual and non virtual methods
• Exception handling
• Accessing Java arrays
Using native code
Performance
• Most applications don’t need native code!
• Only for extensive calculations: games, rich media
• Take advantage of NEON CPU instructions
• Avoiding Java Garbage Collection
Cross-platform architecture
platform independent code
(no JNI)
platform dependant libraries
(network, UI, etc)
external interface (JNI/Objective-C)
Application (Java/UIKit)
Cross-platform examples
VLC
Security
1. Register as a developer (£60 per year) 2. Add device UUID to dev account 3. Generate Provisioning Profile 4. Sign APK with developer’s certificate !or Submit to Apple Store or Jailbreak device
Binary is encrypted Decryption is on OS level
Self-signed APK or not-signed at all
Decompiled Objective C: class structures assembly code
Decompiled Java: readable code
Demo
DISCLAIMER: For educational purposes only; I’m not encouraging to hack somebody else’s applications;
Summary
• Always obfuscate Java code!
• Never save passwords, use session key or hash instead
• Never keep encryption keys in clear data in memory
• Keep all critical code in native
Further protection
• Hide non-public symbols from .so files
• Strip debug information into separate files
• Expose only high-level APIs to Java
Tips
• Debugging native code is tricky
• Linux or OSX as dev platform
• Use ARM DS-5 Community Edition in Eclipse
• Android fragmentation
• separate .so files for different version