Android Native Development
Kit (NDK)
30.04.2015
Khiem-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 := mylib
LOCAL_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
Queen Game - example C vs Java
static 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);
}
}
}
01.05.201516
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);
}
Queen Game - example C vs Java
01.05.201517
public class MainActivity extends
Activity {
public native String
stringFromJNI();
public native void runQueen(int N);
static {
System.loadLibrary("main");
}
@Override
protected void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.inject(this);
runQueen(200000);
}
…
Queen Game - example C vs Java
01.05.201518
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);
}
}
Makefile(s) needed
• Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := main
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_SRC_FILES := main.c queengame.c threadexample.c
LOCAL_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
01.05.201519
Measure Performance C vs Java
01.05.201520
• 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 men");
• Other C Libraries
• Memory management
• File management
• NativeThreads
• Time
• OpenGL
• ...
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.
01.05.201525
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);
01.05.201526
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
01.05.201527
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
01.05.201528
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);
}
}
01.05.201529
Native Thread Example C side
void 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.");
}
} 01.05.201530
Native Thread Example in Java
public 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;
}
01.05.201531
@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();
}
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
01.05.201532
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>
01.05.201533
C/C++ App (3/3)
• Example Brick Breaker (download code at the link
given from slide 10)
01.05.201534
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
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.
01.05.201540
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
01.05.201541
42 © Computas AS 01.05.2015
Questions?
Computas AS Tel +47 67 83 10 00
Lysaker Torg 45, pb 482 Fax +47 67 83 10 01
1327 Lysaker Org.nr: NO 986 352 325 MVA
Norway www.computas.com
Khiem-Kim Ho Xuan

Android ndk

  • 1.
    Android Native Development Kit(NDK) 30.04.2015 Khiem-Kim Ho Xuan
  • 2.
    Introduction • What isthe Android NDK? • Write, Compile and Embed Native code into Apps • Porting existing C/C++ code
  • 3.
    Android SDK • WriteApps in Java • Resources and compiled codes packed In APK • Get access to the Android Framework • Interpreted by the Dalvik VM
  • 4.
    What is theAndroid 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!
  • 5.
    What is theAndroid NDK? • Download NDK from this page: • https://developer.android.com/tools/sdk/ndk/index. html
  • 6.
    Why use AndroidNDK? • 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
  • 7.
    Why use AndroidNDK? • the NDK will not benefit most apps! • Best for game engines • CPU intensive workload • Signal processing • Physics simulation
  • 8.
    Why use AndroidNDK? • It is not for you… if: • Think Java is complicated: • C/C++ would make it worse • JNI is a headache
  • 9.
  • 10.
    Android Studio • Notan easy setup for Android Studio. • Gradle hack! • Check https://bitbucket.org/khiemkimxuan/ndk
  • 11.
    Creating a NDKproject 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!
  • 12.
    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
  • 13.
  • 14.
    Write your JavaActivity 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"); } }
  • 15.
    Write a Makefile LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := mylib LOCAL_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 Java static 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); } } } 01.05.201516 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 01.05.201517 public class MainActivity extends Activity { public native String stringFromJNI(); public native void runQueen(int N); static { System.loadLibrary("main"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.inject(this); runQueen(200000); } …
  • 18.
    Queen Game -example C vs Java 01.05.201518 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 := main LOCAL_C_INCLUDES := $(LOCAL_PATH) LOCAL_SRC_FILES := main.c queengame.c threadexample.c LOCAL_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 01.05.201519
  • 20.
    Measure Performance Cvs Java 01.05.201520 • Queen Game: • C: 0.00001 • Java: 0.00222 • Fibonacci: • C Result: 0.01251 • Java: 0.04512
  • 21.
    The C/C++ side ... jintJNICALL 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, ...); ... };
  • 22.
    Java Primitive TypeData 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
  • 23.
    Java Reference TypesMapping 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
  • 24.
    Usage of Libraries •Android Log library • Log message to LogCat __android_log_print(ANDROID_LOG_INFO,"TAG","Message men"); • Other C Libraries • Memory management • File management • NativeThreads • Time • OpenGL • ...
  • 25.
    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. 01.05.201525
  • 26.
    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); 01.05.201526
  • 27.
    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 01.05.201527
  • 28.
    Native Threads (POSIXThreads) • 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 01.05.201528
  • 29.
    Native Thread ExampleC 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); } } 01.05.201529
  • 30.
    Native Thread ExampleC side void 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."); } } 01.05.201530
  • 31.
    Native Thread Examplein Java public 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; } 01.05.201531 @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(); }
  • 32.
    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 01.05.201532
  • 33.
    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> 01.05.201533
  • 34.
    C/C++ App (3/3) •Example Brick Breaker (download code at the link given from slide 10) 01.05.201534
  • 35.
    Port legacy codesC/C++ • Standalone toolchain!
  • 36.
    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
  • 37.
    Example of StandaloneToolchain • 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. 01.05.201540
  • 38.
    Thank you forlistening! “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 01.05.201541
  • 39.
    42 © ComputasAS 01.05.2015 Questions? Computas AS Tel +47 67 83 10 00 Lysaker Torg 45, pb 482 Fax +47 67 83 10 01 1327 Lysaker Org.nr: NO 986 352 325 MVA Norway www.computas.com Khiem-Kim Ho Xuan

Editor's Notes

  • #4 APK = Android Application Package Dalvik VM = specialized for mobile embedded systems to run applications The Android runtime also provides a set of core libraries which enable Android application developers to write Android applications using standard Java programming language.
  • #5 However, we can still use SDK without NDK Ability to cross-compile C/C++ and even Assembly code to Android embedded systems Cross compilation toolchain based on GCC
  • #6 However, we can still use SDK without NDK Ability to cross-compile C/C++ and even Assembly code to Android embedded systems Cross compilation toolchain based on GCC
  • #9 Most Android apps should just work without any changes under ART. However, some techniques that work on Dalvik do not work on ART. For information about the most important issues, see Verifying App Behavior on the Android Runtime (ART). Pay particular attention if: Your app uses Java Native Interface (JNI) to run C/C++ code. You use development tools that generate non-standard code (such as some obfuscators). You use techniques that are incompatible with compacting garbage collection. Ahead-of-time (AOT) compilation GC improved " 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
  • #10 Need a way to tie Java and Native code together! Java Native Interface(JNI), a 2-way bridge: Java code can call Native code Native code can callback Java code Based on a Reflection-like API
  • #13 Extern C tells the compiler to give the method C linkage recognized only by C++. JNIEXPORT have to have it so that it appears in the built binary (.so file) JNICALL tell which method to use from C to Java JNIEnv is the pointer to the interface of JVM jstring JNICALL defines the return of the method as a Java compatible string
  • #17 N*n chessboard no queen is on the same row, column or diagonal as another queen (no queen should threaten another queen).
  • #19 v
  • #20 Android.mk is for one individual solution. if many makefiles. Application.mk should be used because it is for the whole project. 
  • #22 reflection for accessing and manipulating classes, fields, methods, and constructors.
  • #27 Realloc only works when you have allocated memory
  • #29 Threads must attach themselves to the Java VM to interact with the java code. If you start the Posix thread, is unable to interact with the Android Java layer, mainly because the POSIX threadcannot directly call JNIEnv .  So we need to put the native thread associated with the JVM, it can obtain JNIEnv. No JNIEnv is not a callback JAVA layer method.
  • #33 Compiler strips away the native_app_glue.o, that is why we have to add app_dummy to avoid that
  • #34 Our activity is the built-in NativeActivity framework class.
  • #35 Compiler strips away the native_app_glue.o, that is why we have to add app_dummy to avoid that
  • #36 arm-linux-androideabi-as test.s -o test.o arm-linux-androideabi-ld --sysroot \path\to\android-ndk\platforms\android-3\arch-arm -o test test.o -lc push to phone : adb push test /data/local/tmp/test adb shell chmod 0755 /data/local/tmp/test adb shell  cd /data/local/tmp ./test On ARM processors you have 16 registers. Actually, that is not entirely true. ARM processors have 32 registers, each 32 bits wide. ARM processors have different programming modes to distinguish user-level and system-level access. Only some registers are visible in each mode. In the user-level mode you can access 16 registers. This is the mode you will use most frequently, so you can ignore the entire mode stuff for now. By the time you need to write Linux device drivers, you will be well past this introduction. The registers are called r0-r15, and the last four are special. r12: IP, or Intra-Procedure call stack register. This register is used by the linker as a scratch register between procedure calls. A procedure must not modify its value on return. This register isn't used by Linux gcc or glibc, but another system might. r13: SP, or Stack Pointer. This register points to the top of the stack. The stack is area of memory used for local function-specific storage. This storage is reclaimed when the function returns. To allocate space on the stack, we subtract from the stack register. To allocate one 32-bit value, we subtract 4 from the stack pointer. r14: LR, or Link Register. This register holds the return value of a subroutine. When a subroutine is called, the LR is filled with the program counter. r15: PC, or Program Counter. This register holds the address of memory that is currently being executed. There is one more register, the Current Program Status Register (CPSR) that contains values indicating some flags like Negative, Zero, Carry, etc. We'll visit it later, you can't read and write it like a normal register anyway.
  • #37 arm-linux-androideabi-as test.s -o test.o arm-linux-androideabi-ld -s -o test test.o On ARM processors you have 16 registers. Actually, that is not entirely true. ARM processors have 32 registers, each 32 bits wide. ARM processors have different programming modes to distinguish user-level and system-level access. Only some registers are visible in each mode. In the user-level mode you can access 16 registers. This is the mode you will use most frequently, so you can ignore the entire mode stuff for now. By the time you need to write Linux device drivers, you will be well past this introduction. The registers are called r0-r15, and the last four are special. r12: IP, or Intra-Procedure call stack register. This register is used by the linker as a scratch register between procedure calls. A procedure must not modify its value on return. This register isn't used by Linux gcc or glibc, but another system might. r13: SP, or Stack Pointer. This register points to the top of the stack. The stack is area of memory used for local function-specific storage. This storage is reclaimed when the function returns. To allocate space on the stack, we subtract from the stack register. To allocate one 32-bit value, we subtract 4 from the stack pointer. r14: LR, or Link Register. This register holds the return value of a subroutine. When a subroutine is called, the LR is filled with the program counter. r15: PC, or Program Counter. This register holds the address of memory that is currently being executed. There is one more register, the Current Program Status Register (CPSR) that contains values indicating some flags like Negative, Zero, Carry, etc. We'll visit it later, you can't read and write it like a normal register anyway.
  • #38 arm-linux-androideabi-as test.s -o test.o arm-linux-androideabi-ld -s -o test test.o On ARM processors you have 16 registers. Actually, that is not entirely true. ARM processors have 32 registers, each 32 bits wide. ARM processors have different programming modes to distinguish user-level and system-level access. Only some registers are visible in each mode. In the user-level mode you can access 16 registers. This is the mode you will use most frequently, so you can ignore the entire mode stuff for now. By the time you need to write Linux device drivers, you will be well past this introduction. The registers are called r0-r15, and the last four are special. r12: IP, or Intra-Procedure call stack register. This register is used by the linker as a scratch register between procedure calls. A procedure must not modify its value on return. This register isn't used by Linux gcc or glibc, but another system might. r13: SP, or Stack Pointer. This register points to the top of the stack. The stack is area of memory used for local function-specific storage. This storage is reclaimed when the function returns. To allocate space on the stack, we subtract from the stack register. To allocate one 32-bit value, we subtract 4 from the stack pointer. r14: LR, or Link Register. This register holds the return value of a subroutine. When a subroutine is called, the LR is filled with the program counter. r15: PC, or Program Counter. This register holds the address of memory that is currently being executed. There is one more register, the Current Program Status Register (CPSR) that contains values indicating some flags like Negative, Zero, Carry, etc. We'll visit it later, you can't read and write it like a normal register anyway.
  • #40 arm-linux-androideabi-gcc-4.9 -fPIE -pie --sysroot C:\android-ndk-r10d\platforms\android-21\arch-arm\ test.c -o test Remember CHMOD 0755 SYSROOT IS AN ENVIRONMENT VARIABLE TO LOCATE DEVICE SYSTEM LIBRARIES adb push /path/to/executable /data/local/tmp adb shell chmod 0755 /data/local/tmp/executable adb shell 'cd /data/local/tmp && ./executable'
  • #41 C:\Users\kkh\Downloads>arm-linux-androideabi-gcc-4.9 -fPIE -pie --sysroot %NDK_SYSROOT% client.c -o client adb push client /data/local/tmp/client adb shell chmod 0755 /data/local/tmp/client Log into adb shell and run it on /data/local/tmp i686-linux-android-gcc-4.9 -fPIE -pie --sysroot $env:X86_SYSROOT client.c -o client