SlideShare a Scribd company logo
JNI
Karol Wrótniak
• Java Native Interface
• Native:
• Platform-specific shared library (.dll, .so, .dylib)
• Non-hybrid mobile app, React Native
• C, C++
• Call native functions from Java and vice versa
• Other JVM languages supported
• JNI ≠ JNA
Overview
• Implement operations not achievable in pure Java:
• System clock - System.currentTimeMillis()
• Filesystem access
• Sockets (e.g. for HTTP requests)
• Reuse existing native libraries
• Hinder reverse-engineering
• Increase performance (in certain cases only):
• computation
Why JNI?
Sample projects using JNI
static {
System.loadLibrary("foo");
}
public native int getTextLength(String text);
Foo.java:
static {
System.loadLibrary("foo");
}
public native int getTextLength(String text);
Foo.java:
static {
System.loadLibrary("foo");
}
public native int getTextLength(String text);
#include <jni.h>
JNIEXPORT
jint
JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength(
JNIEnv *env,
jobject thiz,
jstring text
) {
return (*env)->GetStringUTFLength(env, text);
}
foo.c:
Foo.java:
static {
System.loadLibrary("foo");
}
public native int getTextLength(String text);
#include <jni.h>
JNIEXPORT
jint
JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength(
JNIEnv *env,
jobject thiz,
jstring text
) {
return (*env)->GetStringUTFLength(env, text);
}
foo.c:
Foo.java:
static {
System.loadLibrary("foo");
}
public native int getTextLength(String text);
#include <jni.h>
JNIEXPORT
jint
JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength(
JNIEnv *env,
jobject thiz,
jstring text
) {
return (*env)->GetStringUTFLength(env, text);
}
foo.c:
Foo.java:
static {
System.loadLibrary("foo");
}
public native int getTextLength(String text);
#include <jni.h>
JNIEXPORT
jint
JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength(
JNIEnv *env,
jobject thiz,
jstring text
) {
return (*env)->GetStringUTFLength(env, text);
}
foo.c:
Foo.java:
static {
System.loadLibrary("foo");
}
public native int getTextLength(String text);
#include <jni.h>
JNIEXPORT
jint
JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength(
JNIEnv *env,
jobject thiz,
jstring text
) {
return (*env)->GetStringUTFLength(env, text);
}
foo.c:
Foo.java:
static {
System.loadLibrary("foo");
}
public native int getTextLength(String text);
#include <jni.h>
JNIEXPORT
jint
JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength(
JNIEnv *env,
jobject thiz,
jstring text
) {
return (*env)->GetStringUTFLength(env, text);
}
foo.c:
Foo.java:
static {
System.loadLibrary("foo");
}
public native int getTextLength(String text);
#include <jni.h>
JNIEXPORT
jint
JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength(
JNIEnv *env,
jobject thiz,
jstring text
) {
return (*env)->GetStringUTFLength(env, text);
}
foo.c:
Foo.java:
static {
System.loadLibrary("foo");
}
public native int getTextLength(String text);
#include <jni.h>
JNIEXPORT
jint
JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength(
JNIEnv *env,
jobject thiz,
jstring text
) {
return (*env)->GetStringUTFLength(env, text);
}
foo.c:
Foo.java:
static {
System.loadLibrary("foo");
}
public native int getTextLength(String text);
#include <jni.h>
JNIEXPORT
jint
JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength(
JNIEnv *env,
jobject thiz,
jstring text
) {
return (*env)->GetStringUTFLength(env, text);
}
foo.c:
Foo.java:
static {
System.loadLibrary("foo");
}
public native int getTextLength(String text);
#include <jni.h>
JNIEXPORT
jint
JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength(
JNIEnv *env,
jobject thiz,
jstring text
) {
return (*env)->GetStringUTFLength(env, text);
}
foo.c:
Foo.java:
• System.loadLibrary("foo")
• System.mapLibraryName("foo") ➔ "libfoo.so"
• java.library.path property
• System.load("/usr/local/lib/libfoo.so")
Java API
• jbyte, jchar, jshort, jint, jlong, jfloat, jdouble
• jboolean: JNI_TRUE, JNI_FALSE
• jstring, jthrowable
• jarray, jintarray...
• jclass, jobject
• jmethodID, jfieldID
JNI types
Calling Java from C
jclass mathClass = (*env)->FindClass(env, "java/lang/Math");
jmethodID minMethodID = (*env)->GetStaticMethodID(env, mathClass,
"min", "(JJ)J");
jlong min = (*env)->CallStaticLongMethod(env, mathClass,
minMethodID, x, y);
public static long min(long a, long b)
Calling Java from C
jclass mathClass = (*env)->FindClass(env, "java/lang/Math");
jmethodID minMethodID = (*env)->GetStaticMethodID(env, mathClass,
"min", "(JJ)J");
jlong min = (*env)->CallStaticLongMethod(env, mathClass,
minMethodID, x, y);
public static long min(long a, long b)
Calling Java from C
jclass mathClass = (*env)->FindClass(env, "java/lang/Math");
jmethodID minMethodID = (*env)->GetStaticMethodID(env, mathClass,
"min", "(JJ)J");
jlong min = (*env)->CallStaticLongMethod(env, mathClass,
minMethodID, x, y);
public static long min(long a, long b)
Calling Java methods
jclass mathClass = (*env)->FindClass(env, "java/lang/Math");
jmethodID minMethodID = (*env)->GetStaticMethodID(env, mathClass,
"min", "(JJ)J");
jlong min = (*env)->CallStaticLongMethod(env, mathClass,
minMethodID, x, y);
public static long min(long a, long b)
Accessing Java fields
jobject calendar = …
jclass calendar_class = (*env)->GetObjectClass(env, calendar);
jfieldID time_field_id = (*env)->GetFieldID(env, calendar_class,
"time", "J");
jlong time = (*env)->GetLongField(env, calendar, time_field_id);
Creating Java objects
jclass foo_class = (*env)->FindClass(env,
"pl/droidsonroids/ndkdemo/Foo");
jmethodID constructor_id = (*env)->GetMethodID(env, foo_class,
"<init>", "()V");
jobject foo = (*env)->NewObject(env, foo_class, constructor_id);
Type signatures
Type signature Java type Example
Z boolean
B byte
C char
S short
I int
J long
F float
D double
L<FQCN>; FQCN Lcom/foo/Foo;
[<type> type[] [Z
V void
javap -s <class file>
abstract ArrayList<String> foo(String[] a, boolean b);
([Ljava/lang/String;Z)Ljava/util/ArrayList;
• Local
• Global
• WeakGlobal (weaker than Java Weak and Soft)
Reference types
Local references
JNIEXPORT void JNICALL
Java_pl_droidsonroids_ndkdemo_Foo_foo(
JNIEnv *env,
jobject thiz,
jobject foo
) {
//...
}
Local reference
Global References
jobject persistent_foo;
JNIEXPORT void JNICALL
Java_pl_droidsonroids_ndkdemo_Foo_foo(
JNIEnv *env,
jobject thiz,
jobject foo
) {
persistent_foo = (*env)->NewGlobalRef(env, foo);
}
(*env)->DeleteGlobalRef(env, persistent_foo);
Finalizers
public final class Foo {
@Override
protected void finalize() throws Throwable {
releaseBar(bar);
super.finalize();
}
private final long bar;
public Foo() {
bar = createBar();
}
private native long createBar();
private native void releaseBar(long bar);
...
JNI_OnLoad JNI_OnUnload
void *foo;
JavaVM *global_vm;
JNIEXPORT
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
global_vm = vm;
foo = malloc(1024);
if (foo == NULL) {
return JNI_ERR;
}
return JNI_VERSION_1_8;
}
JNIEXPORT void JNI_OnUnload(JavaVM *vm, void *reserved) {
free(foo);
}
Registering native methods
//Foo.java
public native int plus(int a, int b);
//Foo.c
static jint add(JNIEnv *env, jobject thiz, jint a, jint b) {
return a + b;
}
JNIEXPORT
jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
JNINativeMethod methods[] = {
{"plus", "(II)I", (void *) add}
};
return JNI_VERSION_1_6;
}
Registering native methods
//Foo.java
public native int plus(int a, int b);
//Foo.c
static jint add(JNIEnv *env, jobject thiz, jint a, jint b) {
return a + b;
}
JNIEXPORT
jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
JNINativeMethod methods[] = {
{"plus", "(II)I", (void *) add}
};
JNIEnv *env;
(*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6);
jclass foo_class = (*env)->FindClass(env,
"pl/droidsonroids/ndkdemo/Foo");
(*env)->RegisterNatives(env, foo_class, methods, 1);
return JNI_VERSION_1_6;
}
Registering native methods
//Foo.java
public native int plus(int a, int b);
//Foo.c
static jint add(JNIEnv *env, jobject thiz, jint a, jint b) {
return a + b;
}
• JNI functions:
• ExceptionCheck
• ExceptionOccured
• ExceptionClear
• FatalError
• ExceptionDescribe
Handling exceptions
(*env)->CallVoidMethod(env, foo, fooMethodID);
if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
(*env)->ExceptionClear(env);
(*env)->CallVoidMethod(env, foo, barMethodID);
}
Catching exceptions
catch
• Need to clear exception or return before JNI calls
Arrays
JNIEXPORT void JNICALL
Java_pl_droidsonroids_ndkdemo_Foo_foo(JNIEnv *env, jobject thiz,
jintArray points) {
jsize length = (*env)->GetArrayLength(env, points);
jint *native_points = (*env)->GetIntArrayElements(env, points,
NULL);
//...
(*env)->ReleaseIntArrayElements(env, points, native_points, 0);
}
Arrays
JNIEXPORT void JNICALL
Java_pl_droidsonroids_ndkdemo_Foo_foo(JNIEnv *env, jobject thiz,
jintArray points) {
jsize length = (*env)->GetArrayLength(env, points);
jint *native_points = (*env)->GetIntArrayElements(env, points,
NULL);
//...
(*env)->ReleaseIntArrayElements(env, points, native_points, 0);
}
Arrays
JNIEXPORT void JNICALL
Java_pl_droidsonroids_ndkdemo_Foo_foo(JNIEnv *env, jobject thiz,
jintArray points) {
jsize length = (*env)->GetArrayLength(env, points);
jint *native_points = (*env)->GetIntArrayElements(env, points,
NULL);
//...
(*env)->ReleaseIntArrayElements(env, points, native_points, 0);
}
Release mode
Arrays
JNIEXPORT void JNICALL
Java_pl_droidsonroids_ndkdemo_Foo_foo(JNIEnv *env, jobject thiz,
jintArray points) {
jsize length = (*env)->GetArrayLength(env, points);
jint *native_points = (*env)->GetIntArrayElements(env, points,
NULL);
//...
(*env)->ReleaseIntArrayElements(env, points, native_points, 0);
}
*isCopy
JNIEXPORT void JNICALL
Java_pl_droidsonroids_ndkdemo_Foo_foo(JNIEnv *env, jobject thiz, jintArray
points) {
jsize start = 0;
jsize size = 2;
jint native_points[2];
(*env)->GetIntArrayRegion(env, points, start, size, native_points);
native_points[0] = native_points[1];
(*env)->SetIntArrayRegion(env, points, start, size, native_points);
}
Arrays
JNIEXPORT void JNICALL
Java_pl_droidsonroids_ndkdemo_Foo_foo(JNIEnv *env, jobject thiz,
jintArray points) {
jsize length = (*env)->GetArrayLength(env, points);
jint *native_points = (*env)->GetIntArrayElements(env, points,
NULL);
//...
(*env)->ReleaseIntArrayElements(env, points, native_points, 0);
}
JNIEXPORT void JNICALL
Java_pl_droidsonroids_ndkdemo_Foo_foo(JNIEnv *env, jobject thiz, jintArray
points) {
jsize start = 0;
jsize size = 2;
jint native_points[2];
(*env)->GetIntArrayRegion(env, points, start, size, native_points);
native_points[0] = native_points[1];
(*env)->SetIntArrayRegion(env, points, start, size, native_points);
}
Arrays
JNIEXPORT void JNICALL
Java_pl_droidsonroids_ndkdemo_Foo_foo(JNIEnv *env, jobject thiz,
jintArray points) {
jsize length = (*env)->GetArrayLength(env, points);
jint *native_points = (*env)->GetIntArrayElements(env, points,
NULL);
//...
(*env)->ReleaseIntArrayElements(env, points, native_points, 0);
}
GC compaction
• Disable GC between Get and Release
• Pin
• Copy
Java heap
native heap
Mode Copy back Free buffer
0 ✓ ✓
JNI_COMMIT ✓ ❌
JNI_ABORT ❌ ✓
Release modes & isCopy
Need to release with another mode
*isCopy == JNI_FALSE:
• skip useless commit
• restore original contents before abort
Direct byte buffers
ByteBuffer.allocateDirect(1024);
void *foo = (*env)->GetDirectBufferAddress(env, buffer);
jlong capacity = (*env)->GetDirectBufferCapacity(env, buffer);
1. Java Native Interface Specification
2. JNI Tips
3. The Java™ Native Interface
Programmer’s Guide and Specification
References
Q&A
Android dev @DroidsOnRoids
Co-organizer @GDG Wrocław
karol.wrotniak@droidsonroids.pl
koral--
Karol Wrótniak
karol-wrotniak
@karol.wrotniak

More Related Content

PDF
JNI - Java & C in the same project
PDF
5. Ввод-вывод, доступ к файловой системе
KEY
Groovy 1.8の新機能について
PDF
Let's go Developer 2011 sendai Let's go Java Developer (Programming Language ...
PPT
Lo Mejor Del Pdc2008 El Futrode C#
PDF
Easy Going Groovy 2nd season on DevLOVE
PDF
3. Объекты, классы и пакеты в Java
PDF
sizeof(Object): how much memory objects take on JVMs and when this may matter
JNI - Java & C in the same project
5. Ввод-вывод, доступ к файловой системе
Groovy 1.8の新機能について
Let's go Developer 2011 sendai Let's go Java Developer (Programming Language ...
Lo Mejor Del Pdc2008 El Futrode C#
Easy Going Groovy 2nd season on DevLOVE
3. Объекты, классы и пакеты в Java
sizeof(Object): how much memory objects take on JVMs and when this may matter

What's hot (20)

PDF
响应式编程及框架
PDF
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloading
PDF
Kotlin coroutine - the next step for RxJava developer?
ZIP
Cleanup and new optimizations in WPython 1.1
PDF
The Evolution of Async-Programming on .NET Platform (TUP, Full)
PDF
JCConf 2015 - 輕鬆學google的雲端開發 - Google App Engine入門(上)
PDF
Metaprogramming and Reflection in Common Lisp
PDF
A deep dive into PEP-3156 and the new asyncio module
PDF
Apache Commons - Don\'t re-invent the wheel
PDF
Jscex: Write Sexy JavaScript
PDF
.NET Multithreading and File I/O
PDF
Construire une application JavaFX 8 avec gradle
PDF
Java 7 at SoftShake 2011
PDF
Java 7 JUG Summer Camp
PPTX
What’s new in C# 6
PDF
#JavaFX.forReal() - ElsassJUG
PDF
Proxies are Awesome!
PDF
Jscex: Write Sexy JavaScript (中文)
PDF
Planet-HTML5-Game-Engine Javascript Performance Enhancement
PDF
The Evolution of Async-Programming (SD 2.0, JavaScript)
响应式编程及框架
Riga DevDays 2017 - The hitchhiker’s guide to Java class reloading
Kotlin coroutine - the next step for RxJava developer?
Cleanup and new optimizations in WPython 1.1
The Evolution of Async-Programming on .NET Platform (TUP, Full)
JCConf 2015 - 輕鬆學google的雲端開發 - Google App Engine入門(上)
Metaprogramming and Reflection in Common Lisp
A deep dive into PEP-3156 and the new asyncio module
Apache Commons - Don\'t re-invent the wheel
Jscex: Write Sexy JavaScript
.NET Multithreading and File I/O
Construire une application JavaFX 8 avec gradle
Java 7 at SoftShake 2011
Java 7 JUG Summer Camp
What’s new in C# 6
#JavaFX.forReal() - ElsassJUG
Proxies are Awesome!
Jscex: Write Sexy JavaScript (中文)
Planet-HTML5-Game-Engine Javascript Performance Enhancement
The Evolution of Async-Programming (SD 2.0, JavaScript)
Ad

Similar to JNI - Java & C in the same project (20)

PPTX
Android ndk
PDF
Android and cpp
KEY
JavaOne 2012 - JVM JIT for Dummies
PPTX
A topology of memory leaks on the JVM
PPTX
Get started with YUI
ODP
Supercharging reflective libraries with InvokeDynamic
PDF
JRuby and Invokedynamic - Japan JUG 2015
PPTX
Dynamic C#
PDF
Why is Java relevant? New features of Java8
PDF
Griffon @ Svwjug
PDF
Node intro
PPTX
C# 6.0 Preview
PDF
Java ppt Gandhi Ravi (gandhiri@gmail.com)
KEY
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
PDF
Java 5 and 6 New Features
KEY
CouchDB on Android
PDF
Using the Android Native Development Kit (NDK)
PPT
比XML更好用的Java Annotation
PDF
Json generation
PPT
JDK1.7 features
Android ndk
Android and cpp
JavaOne 2012 - JVM JIT for Dummies
A topology of memory leaks on the JVM
Get started with YUI
Supercharging reflective libraries with InvokeDynamic
JRuby and Invokedynamic - Japan JUG 2015
Dynamic C#
Why is Java relevant? New features of Java8
Griffon @ Svwjug
Node intro
C# 6.0 Preview
Java ppt Gandhi Ravi (gandhiri@gmail.com)
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
Java 5 and 6 New Features
CouchDB on Android
Using the Android Native Development Kit (NDK)
比XML更好用的Java Annotation
Json generation
JDK1.7 features
Ad

Recently uploaded (20)

PPTX
history of c programming in notes for students .pptx
PDF
medical staffing services at VALiNTRY
PDF
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
PDF
PTS Company Brochure 2025 (1).pdf.......
PPTX
Reimagine Home Health with the Power of Agentic AI​
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PPTX
VVF-Customer-Presentation2025-Ver1.9.pptx
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PDF
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
PDF
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PDF
Adobe Illustrator 28.6 Crack My Vision of Vector Design
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
history of c programming in notes for students .pptx
medical staffing services at VALiNTRY
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
PTS Company Brochure 2025 (1).pdf.......
Reimagine Home Health with the Power of Agentic AI​
How to Migrate SBCGlobal Email to Yahoo Easily
VVF-Customer-Presentation2025-Ver1.9.pptx
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
Design an Analysis of Algorithms II-SECS-1021-03
How to Choose the Right IT Partner for Your Business in Malaysia
Odoo Companies in India – Driving Business Transformation.pdf
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
Which alternative to Crystal Reports is best for small or large businesses.pdf
Adobe Illustrator 28.6 Crack My Vision of Vector Design
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus

JNI - Java & C in the same project

  • 2. • Java Native Interface • Native: • Platform-specific shared library (.dll, .so, .dylib) • Non-hybrid mobile app, React Native • C, C++ • Call native functions from Java and vice versa • Other JVM languages supported • JNI ≠ JNA Overview
  • 3. • Implement operations not achievable in pure Java: • System clock - System.currentTimeMillis() • Filesystem access • Sockets (e.g. for HTTP requests) • Reuse existing native libraries • Hinder reverse-engineering • Increase performance (in certain cases only): • computation Why JNI?
  • 5. static { System.loadLibrary("foo"); } public native int getTextLength(String text); Foo.java:
  • 6. static { System.loadLibrary("foo"); } public native int getTextLength(String text); Foo.java:
  • 7. static { System.loadLibrary("foo"); } public native int getTextLength(String text); #include <jni.h> JNIEXPORT jint JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength( JNIEnv *env, jobject thiz, jstring text ) { return (*env)->GetStringUTFLength(env, text); } foo.c: Foo.java:
  • 8. static { System.loadLibrary("foo"); } public native int getTextLength(String text); #include <jni.h> JNIEXPORT jint JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength( JNIEnv *env, jobject thiz, jstring text ) { return (*env)->GetStringUTFLength(env, text); } foo.c: Foo.java:
  • 9. static { System.loadLibrary("foo"); } public native int getTextLength(String text); #include <jni.h> JNIEXPORT jint JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength( JNIEnv *env, jobject thiz, jstring text ) { return (*env)->GetStringUTFLength(env, text); } foo.c: Foo.java:
  • 10. static { System.loadLibrary("foo"); } public native int getTextLength(String text); #include <jni.h> JNIEXPORT jint JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength( JNIEnv *env, jobject thiz, jstring text ) { return (*env)->GetStringUTFLength(env, text); } foo.c: Foo.java:
  • 11. static { System.loadLibrary("foo"); } public native int getTextLength(String text); #include <jni.h> JNIEXPORT jint JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength( JNIEnv *env, jobject thiz, jstring text ) { return (*env)->GetStringUTFLength(env, text); } foo.c: Foo.java:
  • 12. static { System.loadLibrary("foo"); } public native int getTextLength(String text); #include <jni.h> JNIEXPORT jint JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength( JNIEnv *env, jobject thiz, jstring text ) { return (*env)->GetStringUTFLength(env, text); } foo.c: Foo.java:
  • 13. static { System.loadLibrary("foo"); } public native int getTextLength(String text); #include <jni.h> JNIEXPORT jint JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength( JNIEnv *env, jobject thiz, jstring text ) { return (*env)->GetStringUTFLength(env, text); } foo.c: Foo.java:
  • 14. static { System.loadLibrary("foo"); } public native int getTextLength(String text); #include <jni.h> JNIEXPORT jint JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength( JNIEnv *env, jobject thiz, jstring text ) { return (*env)->GetStringUTFLength(env, text); } foo.c: Foo.java:
  • 15. static { System.loadLibrary("foo"); } public native int getTextLength(String text); #include <jni.h> JNIEXPORT jint JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength( JNIEnv *env, jobject thiz, jstring text ) { return (*env)->GetStringUTFLength(env, text); } foo.c: Foo.java:
  • 16. static { System.loadLibrary("foo"); } public native int getTextLength(String text); #include <jni.h> JNIEXPORT jint JNICALL Java_pl_droidsonroids_ndkdemo_Foo_getTextLength( JNIEnv *env, jobject thiz, jstring text ) { return (*env)->GetStringUTFLength(env, text); } foo.c: Foo.java:
  • 17. • System.loadLibrary("foo") • System.mapLibraryName("foo") ➔ "libfoo.so" • java.library.path property • System.load("/usr/local/lib/libfoo.so") Java API
  • 18. • jbyte, jchar, jshort, jint, jlong, jfloat, jdouble • jboolean: JNI_TRUE, JNI_FALSE • jstring, jthrowable • jarray, jintarray... • jclass, jobject • jmethodID, jfieldID JNI types
  • 19. Calling Java from C jclass mathClass = (*env)->FindClass(env, "java/lang/Math"); jmethodID minMethodID = (*env)->GetStaticMethodID(env, mathClass, "min", "(JJ)J"); jlong min = (*env)->CallStaticLongMethod(env, mathClass, minMethodID, x, y); public static long min(long a, long b)
  • 20. Calling Java from C jclass mathClass = (*env)->FindClass(env, "java/lang/Math"); jmethodID minMethodID = (*env)->GetStaticMethodID(env, mathClass, "min", "(JJ)J"); jlong min = (*env)->CallStaticLongMethod(env, mathClass, minMethodID, x, y); public static long min(long a, long b)
  • 21. Calling Java from C jclass mathClass = (*env)->FindClass(env, "java/lang/Math"); jmethodID minMethodID = (*env)->GetStaticMethodID(env, mathClass, "min", "(JJ)J"); jlong min = (*env)->CallStaticLongMethod(env, mathClass, minMethodID, x, y); public static long min(long a, long b)
  • 22. Calling Java methods jclass mathClass = (*env)->FindClass(env, "java/lang/Math"); jmethodID minMethodID = (*env)->GetStaticMethodID(env, mathClass, "min", "(JJ)J"); jlong min = (*env)->CallStaticLongMethod(env, mathClass, minMethodID, x, y); public static long min(long a, long b)
  • 23. Accessing Java fields jobject calendar = … jclass calendar_class = (*env)->GetObjectClass(env, calendar); jfieldID time_field_id = (*env)->GetFieldID(env, calendar_class, "time", "J"); jlong time = (*env)->GetLongField(env, calendar, time_field_id);
  • 24. Creating Java objects jclass foo_class = (*env)->FindClass(env, "pl/droidsonroids/ndkdemo/Foo"); jmethodID constructor_id = (*env)->GetMethodID(env, foo_class, "<init>", "()V"); jobject foo = (*env)->NewObject(env, foo_class, constructor_id);
  • 25. Type signatures Type signature Java type Example Z boolean B byte C char S short I int J long F float D double L<FQCN>; FQCN Lcom/foo/Foo; [<type> type[] [Z V void javap -s <class file> abstract ArrayList<String> foo(String[] a, boolean b); ([Ljava/lang/String;Z)Ljava/util/ArrayList;
  • 26. • Local • Global • WeakGlobal (weaker than Java Weak and Soft) Reference types
  • 27. Local references JNIEXPORT void JNICALL Java_pl_droidsonroids_ndkdemo_Foo_foo( JNIEnv *env, jobject thiz, jobject foo ) { //... } Local reference
  • 28. Global References jobject persistent_foo; JNIEXPORT void JNICALL Java_pl_droidsonroids_ndkdemo_Foo_foo( JNIEnv *env, jobject thiz, jobject foo ) { persistent_foo = (*env)->NewGlobalRef(env, foo); } (*env)->DeleteGlobalRef(env, persistent_foo);
  • 29. Finalizers public final class Foo { @Override protected void finalize() throws Throwable { releaseBar(bar); super.finalize(); } private final long bar; public Foo() { bar = createBar(); } private native long createBar(); private native void releaseBar(long bar); ...
  • 30. JNI_OnLoad JNI_OnUnload void *foo; JavaVM *global_vm; JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { global_vm = vm; foo = malloc(1024); if (foo == NULL) { return JNI_ERR; } return JNI_VERSION_1_8; } JNIEXPORT void JNI_OnUnload(JavaVM *vm, void *reserved) { free(foo); }
  • 31. Registering native methods //Foo.java public native int plus(int a, int b); //Foo.c static jint add(JNIEnv *env, jobject thiz, jint a, jint b) { return a + b; }
  • 32. JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { JNINativeMethod methods[] = { {"plus", "(II)I", (void *) add} }; return JNI_VERSION_1_6; } Registering native methods //Foo.java public native int plus(int a, int b); //Foo.c static jint add(JNIEnv *env, jobject thiz, jint a, jint b) { return a + b; }
  • 33. JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { JNINativeMethod methods[] = { {"plus", "(II)I", (void *) add} }; JNIEnv *env; (*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6); jclass foo_class = (*env)->FindClass(env, "pl/droidsonroids/ndkdemo/Foo"); (*env)->RegisterNatives(env, foo_class, methods, 1); return JNI_VERSION_1_6; } Registering native methods //Foo.java public native int plus(int a, int b); //Foo.c static jint add(JNIEnv *env, jobject thiz, jint a, jint b) { return a + b; }
  • 34. • JNI functions: • ExceptionCheck • ExceptionOccured • ExceptionClear • FatalError • ExceptionDescribe Handling exceptions
  • 35. (*env)->CallVoidMethod(env, foo, fooMethodID); if ((*env)->ExceptionCheck(env) == JNI_TRUE) { (*env)->ExceptionClear(env); (*env)->CallVoidMethod(env, foo, barMethodID); } Catching exceptions catch • Need to clear exception or return before JNI calls
  • 36. Arrays JNIEXPORT void JNICALL Java_pl_droidsonroids_ndkdemo_Foo_foo(JNIEnv *env, jobject thiz, jintArray points) { jsize length = (*env)->GetArrayLength(env, points); jint *native_points = (*env)->GetIntArrayElements(env, points, NULL); //... (*env)->ReleaseIntArrayElements(env, points, native_points, 0); }
  • 37. Arrays JNIEXPORT void JNICALL Java_pl_droidsonroids_ndkdemo_Foo_foo(JNIEnv *env, jobject thiz, jintArray points) { jsize length = (*env)->GetArrayLength(env, points); jint *native_points = (*env)->GetIntArrayElements(env, points, NULL); //... (*env)->ReleaseIntArrayElements(env, points, native_points, 0); }
  • 38. Arrays JNIEXPORT void JNICALL Java_pl_droidsonroids_ndkdemo_Foo_foo(JNIEnv *env, jobject thiz, jintArray points) { jsize length = (*env)->GetArrayLength(env, points); jint *native_points = (*env)->GetIntArrayElements(env, points, NULL); //... (*env)->ReleaseIntArrayElements(env, points, native_points, 0); } Release mode
  • 39. Arrays JNIEXPORT void JNICALL Java_pl_droidsonroids_ndkdemo_Foo_foo(JNIEnv *env, jobject thiz, jintArray points) { jsize length = (*env)->GetArrayLength(env, points); jint *native_points = (*env)->GetIntArrayElements(env, points, NULL); //... (*env)->ReleaseIntArrayElements(env, points, native_points, 0); } *isCopy
  • 40. JNIEXPORT void JNICALL Java_pl_droidsonroids_ndkdemo_Foo_foo(JNIEnv *env, jobject thiz, jintArray points) { jsize start = 0; jsize size = 2; jint native_points[2]; (*env)->GetIntArrayRegion(env, points, start, size, native_points); native_points[0] = native_points[1]; (*env)->SetIntArrayRegion(env, points, start, size, native_points); } Arrays JNIEXPORT void JNICALL Java_pl_droidsonroids_ndkdemo_Foo_foo(JNIEnv *env, jobject thiz, jintArray points) { jsize length = (*env)->GetArrayLength(env, points); jint *native_points = (*env)->GetIntArrayElements(env, points, NULL); //... (*env)->ReleaseIntArrayElements(env, points, native_points, 0); }
  • 41. JNIEXPORT void JNICALL Java_pl_droidsonroids_ndkdemo_Foo_foo(JNIEnv *env, jobject thiz, jintArray points) { jsize start = 0; jsize size = 2; jint native_points[2]; (*env)->GetIntArrayRegion(env, points, start, size, native_points); native_points[0] = native_points[1]; (*env)->SetIntArrayRegion(env, points, start, size, native_points); } Arrays JNIEXPORT void JNICALL Java_pl_droidsonroids_ndkdemo_Foo_foo(JNIEnv *env, jobject thiz, jintArray points) { jsize length = (*env)->GetArrayLength(env, points); jint *native_points = (*env)->GetIntArrayElements(env, points, NULL); //... (*env)->ReleaseIntArrayElements(env, points, native_points, 0); }
  • 42. GC compaction • Disable GC between Get and Release • Pin • Copy Java heap native heap
  • 43. Mode Copy back Free buffer 0 ✓ ✓ JNI_COMMIT ✓ ❌ JNI_ABORT ❌ ✓ Release modes & isCopy Need to release with another mode *isCopy == JNI_FALSE: • skip useless commit • restore original contents before abort
  • 44. Direct byte buffers ByteBuffer.allocateDirect(1024); void *foo = (*env)->GetDirectBufferAddress(env, buffer); jlong capacity = (*env)->GetDirectBufferCapacity(env, buffer);
  • 45. 1. Java Native Interface Specification 2. JNI Tips 3. The Java™ Native Interface Programmer’s Guide and Specification References
  • 46. Q&A Android dev @DroidsOnRoids Co-organizer @GDG Wrocław karol.wrotniak@droidsonroids.pl koral-- Karol Wrótniak karol-wrotniak @karol.wrotniak