Top Banner
Android Native Development Kit (NDK) 30.04.2015 Khiem-Kim Ho Xuan
39
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Android ndk

Android Native Development Kit (NDK)

30.04.2015Khiem-Kim Ho Xuan

Page 2: Android ndk

Introduction

• What is the Android NDK?• Write, Compile and Embed Native code into Apps• Porting existing C/C++ code

Page 3: Android ndk

Android SDK

• Write Apps in Java• Resources and

compiled codes packed In APK

• Get access to the Android Framework

• Interpreted by the Dalvik VM

Page 4: Android ndk

What is the Android NDK?

• A tool to Write, Compile and Embed Native code in Apps• Usable for 3 types architecture:

• ARM, X86 and MIPS• Makefile and GDB Debugger support!

Page 5: Android ndk

What is the Android NDK?

• Download NDK from this page:• https://developer.android.com/tools/sdk/ndk/

index.html

Page 6: Android ndk

Why use Android NDK?

• It is for you…. if:• Need performance (Games or intensive Apps)

• Control memory allocation and alignment yourself• Write CPU-intensive operations• Exceed Java Apps memory limitations

• Port C/C++ code• Reuse legacy codes

Page 7: Android ndk

Why use Android NDK?

• the NDK will not benefit most apps! • Best for game engines • CPU intensive workload • Signal processing • Physics simulation

Page 8: Android ndk

Why use Android NDK?

• It is not for you… if:• Think Java is complicated:

• C/C++ would make it worse• JNI is a headache

Page 9: Android ndk

Communication point (JNI)

Page 10: Android ndk

Android Studio

• Not an easy setup for Android Studio. • Gradle hack!• Check https://bitbucket.org/khiemkimxuan/ndk

Page 11: Android ndk

Creating a NDK project with Android Studio

• In short:1. Create an Android project

2. Add new «JNI» folder to the Project.

3. Add ndk.dir=location of ndk, to local.properties file

4. Add hacks on gradle build file (check the link from the previous slide!)

5. C/C++ files and Makefiles must be in the Project’s jni folder

6. Compile it!

1. Binary SO librares generated in /lib/armeabi

7. Alternatively, use standalone toolchain to cross compile C/C++ or Assembly file and run it on adb shell!

Page 12: Android ndk

Write your C/C++ source file

#include <jni.h>#include <string.h>

JNIEXPORT jstring JNICALL Java_com_myproject_MyActivity_getMyData(JNIEnv* pEnv, jobject pThis){ return (*pEnv)->NewStringUTF(pEnv, "My native project talks C, not C++ ok? Pointer difference!!");}

#include <jni.h>#include <string.h>

extern "C"JNIEXPORT jstring JNICALL Java_com_myproject_MyActivity_getMyData(JNIEnv* pEnv, jobject pThis){ return pEnv->NewStringUTF("My native project talks C++, not C ok? Pointer difference!!");}}

C code

C++ code

Page 13: Android ndk

Write your Java Activity

Page 14: Android ndk

Write your Java Activity

package com.myproject;

Import ..............

public class MyActivity extends Activity {

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

setTitle(getMyData());

}

public native String getMyData();

static {

System.loadLibrary("mylib");

}

}

Page 15: Android ndk

Write a Makefile

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := mylibLOCAL_SRC_FILES := MyActivity.c

include $(BUILD_SHARED_LIBRARY)LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv2

# Typical filename should end with .mk. To build, add ndk directory to # System PATH and run ndk-build inside the jni folder.# You should also create Application.mk file that describes APP_ABI #and APP_PLATFORM

Page 16: Android ndk

16

Queen Game - example C vs Javastatic int isConsistent(int q[], int n) { int i; for(i = 0; i < n; i++) { if(q[i] == q[n]) return FALSE; if(q[i] - q[n] == (n - i)) return FALSE; if(q[n] - q[i] == (n-i)) return FALSE; } return TRUE;} static void enumerateRec(int board[], int n) { int board_length = sizeof(board); if(n == board_length) { //print_result(board); } else { int i = 0; for(i = 0; i < board_length; i++) { board[n] = i; if(isConsistent(board,n) == TRUE) enumerateRec(board,n+1); } } }

30.04.2015

static void enumerate(int N) { int board[N]; memset(board,0,sizeof(board)); enumerateRec(board, 0);} JNIEXPORT void JNICALL Java_com_example_kkh_myapplication_MainActivity_runQueen(JNIEnv *env, jobject obj,jint arg) { int n = (int)arg; enumerate(n);}

Page 17: Android ndk

17

Queen Game - example C vs Java

30.04.2015

public class MainActivity extends Activity { public native String stringFromJNI(); public native void runQueen(int N); static { System.loadLibrary("main"); }

@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.inject(this); runQueen(200000); } …

Page 18: Android ndk

18

Queen Game - example C vs Java

30.04.2015

public static boolean isConsistent(int[] q, int n) { for (int i = 0; i < n; i++) { if (q[i] == q[n]) return false; if ((q[i] - q[n]) == (n - i)) return false; if ((q[n] - q[i]) == (n - i)) return false; } return true; }… public static void enumerate(int[] q, int n) { int N = q.length; if (n == N) printQueens(q); else { for (int i = 0; i < N; i++) { q[n] = i; if (isConsistent(q, n)) enumerate(q, n + 1); } } }

public static void enumerate(int N) { int[] a = new int[N]; enumerate(a, 0); }}

Page 19: Android ndk

19

Makefile(s) needed

• Android.mk:LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS) LOCAL_MODULE := mainLOCAL_C_INCLUDES := $(LOCAL_PATH)LOCAL_SRC_FILES := main.c queengame.c threadexample.cLOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv2

include $(BUILD_SHARED_LIBRARY)

• Application.mk:APP_ABI := armeabi armeabi-v7a x86 mips APP_PLATFORM := android-21 #APP_STL := stlport_static

30.04.2015

Page 20: Android ndk

20

Measure Performance C vs Java

30.04.2015

• Queen Game:• C: 0.00001• Java: 0.00222

• Fibonacci:• C Result: 0.01251• Java: 0.04512

Page 21: Android ndk

The C/C++ side...jint JNICALL Java_com_myproject_MyStore_addition (JNIEnv *pEnv, jobject pObj, jint pa, jint pb) { return pa + pb;}...

• JNIEnv allows manipulating the Virtual Machine (functions are mapped to Java methods)

• Java types are mapped to JNI native types • Primitives can be converted to classic C/C++ primitives• Mainly Java Reflection: ...

struct JNINativeInterface { jclass (*FindClass)(JNIEnv*, const char*); jint (*ThrowNew)(JNIEnv *, jclass, const char *); jobject (*NewGlobalRef)(JNIEnv*, jobject); jobject (*NewLocalRef)(JNIEnv*, jobject); jobject (*NewObject)(JNIEnv*, jclass, jmethodID, ...); jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);

jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...); jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...);

...};

Page 22: Android ndk

Java Primitive Type Data

Java Type JNI Type C Type

boolean jboolean unsigned char

byte jbyte signed char

char jchar unsigned short

double jdouble double

float jfloat float

byte jbyte signed char

int jint int

long jlong long long

short jshort short

Page 23: Android ndk

Java Reference Types Mapping

Java Type Native Type

java.lang.Class jclass

java.lang.Throwable jthrowable

java.lang.String jstring

Other objects jobject

java.lang.Object[] jobjectArray

boolean[] jbooleanArray

byte[] jbyteArray

char[] jcharArray

short[] jshortArray

int[] jintArray

long[] jlongArray

float[] jfloatArray

double[] jdoubleArray

Other arrays Jarray

Page 24: Android ndk

Usage of Libraries

• Android Log library• Log message to LogCat

__android_log_print(ANDROID_LOG_INFO,"TAG","Message me\n");

• Other C Libraries • Memory management• File management• NativeThreads• Time• OpenGL• ...

Page 25: Android ndk

15.04.202325

Bionic API (1/3) – Introduction

• Bionic is the POSIX standard C library for Android Platforms

• Best suited for mobile computing and provides lightweight wrapper around kernel.

• Bionic provides C standard library macros, type definitions, functions etc.

• Not every function in the standard C library is supported by Bionic.

Page 26: Android ndk

15.04.202326

Bionic API (2/3) – Memory Management

• Dynamic Memory Management for C• Always include standard C library header:

• #include<stdlib.h>• Allocate Dynamic Memory in C:

• void* malloc(size_t size);• Deallocate Dynamic Memory in C:

• void free(void* memory);• Changing Dynamic Memory Allocation in C:

• void* realloc(void* memory, size_t size);

Page 27: Android ndk

15.04.202327

Bionic API (3/3) – Standard File I/O

• Standard Streams:• stdin: Standard input stream• stdout: Standard output stream• stderr: Standard error stream

• Always include standard I/O C library header:• #include<stdio.h>

• Most file I/O functions can be used:• write: fopen, fwrite, fputs, fputc....• read: fread, fgets, fgetc, fscanf....• seek: fseek

Page 28: Android ndk

15.04.202328

Native Threads (POSIX Threads)

• A part of the Bionic C standard library• #include <pthread.h>

• Pthread functions:• pthread_create, pthread_join,

• The POSIX threads are not known to the Java VM.• Solution? Attach them to the Java VM!

• Use jint JNI_OnLoad (JavaVM *vm, void* reserved) function as it gets invoked by the virtual machine when the shared library is loaded.

• Cannot share JNIEnv, it’s thread local• Use AttachCurrentThread, DetachCurrentThread the thread

before exit

Page 29: Android ndk

29

Native Thread Example C side jint JNI_OnLoad (JavaVM* vm, void* reserved) { jvm1 = vm; return JNI_VERSION_1_6;} void *run_task(void *args) { JNIEnv* env = NULL; int n = (*jvm1)->AttachCurrentThread(jvm1,&env, NULL); if (n == 0) { jstring msg = (*env)->NewStringUTF(env,"Yes Thread Running."); (*env)->CallVoidMethod(env, obj1, mid1, msg); (*env)->DeleteGlobalRef(env,obj1); (*jvm1)->DetachCurrentThread(jvm1); }} 30.04.2015

Page 30: Android ndk

30

Native Thread Example C sidevoid init_instance(JNIEnv *env) { jclass jz1 = (*env)->FindClass(env,"com/example/kkh/myapplication/MainActivity"); jmethodID mid = (*env)->GetMethodID(env,jz1,"<init>","()V"); jobject myobj = (*env)->NewObject(env,jz1,mid); obj1 = (*env)->NewGlobalRef(env,myobj); mid1 = (*env)->GetMethodID(env, jz1, "setMsg", "(Ljava/lang/String;)V"); } JNIEXPORT void JNICALL Java_com_example_kkh_myapplication_MainActivity_startNativeThread (JNIEnv *env) { init_instance(env); pthread_t thread1; int n = pthread_create(&thread1,NULL,run_task,NULL); if (n != 0) { jclass exceptionClazz = (* env)-> FindClass(env,"java/lang/RuntimeException"); (* env)-> ThrowNew(env,exceptionClazz, "create thread error."); } }

30.04.2015

Page 31: Android ndk

31

Native Thread Example in Javapublic class MainActivity extends Activity {

@InjectView(R.id.thread_start_button) Button mStartNativeThreadButton;

public static MainActivity instance; public native void startNativeThread();

static { System.loadLibrary("main"); } @Override protected void onCreate(Bundle savedInstanceState) { … ButterKnife.inject(this); instance = this; }

30.04.2015

@OnClick(R.id.thread_start_button) public void startThreadButton(View v) { if(v.getId() == R.id.thread_start_button) { startNativeThread(); } } public void setMsg(final String msg) {Toast.makeText(instance, msg, Toast.LENGTH_LONG).show();}

Page 32: Android ndk

15.04.202332

C/C++ App (1/3)

• Write only C or C++ app for Android rather than having any Java code.

• Need to specify native_app_glue at the local static library flag.

• Add app_dummy() at android_main() to make sure that the glue isn’t stripped

• Make sure to add android.app.NativeActivity as Android name for the Activity.• http://developer.android.com/reference/android/app/

NativeActivity.html

Page 33: Android ndk

15.04.202333

C/C++ App (2/3)

• In the AndroidManifest.xml ( or create an Activity file and extend android.app.NativeActivity and load the library)

<activity android:name="android.app.NativeActivity" android:configChanges="orientation|keyboardHidden" android:label="@string/app_name" android:screenOrientation="landscape" android:uiOptions="none"> <meta-data android:name="android.app.lib_name" android:value="main" /> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter></activity>

Page 34: Android ndk

15.04.202334

C/C++ App (3/3)

• Example Brick Breaker (download code at the link given from slide 10)

Page 35: Android ndk

Port legacy codes C/C++

• Standalone toolchain!

Page 36: Android ndk

Porting existing C/C++ code

• Cross-compile on cmd or a terminal in Linux!• Commands to cross-compile (add to environment path and remember to

include sysroot platforms):• ARM: arm-linux-androideabi-gcc/g++-<version> --sysroot <path>

<files.c/cpp>…

• Intel X86: i686-linux-android-gcc/g++ --sysroot <path> <files.c/cpp>…

• MIPS: mipsel-linux-android-gcc/g++ --sysroot <path> <files.c/cpp>…

• Build your own NDK Makefile• Example project for porting C code to an existing app:

• The Emerald Programming Language:

https://bitbucket.org/khiemkimxuan/emerald-lite

Page 37: Android ndk

15.04.202340

Example of Standalone Toolchain

• Simple Socket example from Beej Client and Server• Cross compile Client and port it!

• Follow these steps:• <architecture-gcc> -fPIE -pie --sysroot <path of sysroot> filename.c -o

filename• adb push filename /local/data/tmp/filename• adb shell chmod 0755 /local/data/tmp/filename• adb shell <path to filename>• ./filename

• Binary files need permission (chmod that file(s)!).• Android runtime runs binaries only if they have

permission.

Page 38: Android ndk

15.04.202341

Thank you for listening!

“Before downloading the NDK, you should understand that the NDK will not benefit most apps. As a developer, you need to balance its benefits against its drawbacks. Notably, using native code on Android generally does not result in a noticable performance improvement, but it always increases your app complexity. In general, you should only use the NDK if it is essential to your app—never because you simply prefer to program in C/C++.”

– Android Developers

Page 39: Android ndk

42 © Computas AS 15.04.2023

Questions?

Computas AS Tel +47 67 83 10 00Lysaker Torg 45, pb 482 Fax +47 67 83 10 011327 Lysaker Org.nr: NO 986 352 325 MVANorway www.computas.com

Khiem-Kim Ho Xuan