+ All Categories
Home > Mobile > Android ndk

Android ndk

Date post: 06-Aug-2015
Category:
Upload: khiem-kim-ho-xuan
View: 125 times
Download: 6 times
Share this document with a friend
Popular Tags:
39
Android Native Development Kit (NDK) 30.04.2015 Khiem-Kim Ho Xuan
Transcript

Android Native Development Kit (NDK)

30.04.2015Khiem-Kim Ho Xuan

Introduction

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

Android SDK

• Write Apps in Java• Resources and

compiled codes packed In APK

• Get access to the Android Framework

• Interpreted by the Dalvik VM

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!

What is the Android NDK?

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

index.html

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

Why use Android NDK?

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

Why use Android NDK?

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

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

Communication point (JNI)

Android Studio

• Not an easy setup for Android Studio. • Gradle hack!• Check https://bitbucket.org/khiemkimxuan/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!

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

Write your Java Activity

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");

}

}

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

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);}

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); } …

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); }}

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

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

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, ...);

...};

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

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

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• ...

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.

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);

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

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

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

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

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();}

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

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>

15.04.202334

C/C++ App (3/3)

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

Port legacy codes C/C++

• Standalone toolchain!

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

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.

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

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


Recommended