Java Native Interface
The Java Native Interface (JNI) is a programming framework that enables Java code running in a Java Virtual Machine (JVM) to call, and to be called by, native applications (programs specific to a hardware and operating system platform) and libraries written in other languages such as C, C++ and assembly.
Category
- JNI:String: JNI String에 대한 설명
- JNI:DataByPass: JAVA와 JNI의 데이터 전달 방법에 대한 설명.
- NDK (Android)
- JNIEnv
Libraries
Examples
- godot-mobile-midi - 직접 만들고 있는 모바일 MIDI 지원 플러그인
- jni_helper.cpp -
lollipop-dev/service/jni/jni_helper.cpp
Features
JNI의 기능에 대한 설명.
JNI and Threads
멀티스레드를 사용할 경우 다음과 같은 사항을 주의해야 한다.
- JNIEnv pointer는 해당 Thread에서만 Valid하다.
- 이 JNIEnv pointer를 다른 Thread에 전달하거나, Cache하여 다른 Thread에서 사용해선 안된다. JVM에서 동일한 Thread에서의 연속적인 함수 호출에 대해서는 같은 JNIEnv pointer를 전달하지만, 다른 Thread의 함수 호출할 경우에는 다른 JNIEnv pointer 를 전달합니다. 따라서 multi thread programming 에서는 JNIEnv를 cache 하는 것은 실수이다.
- Local reference는 해당 reference를 만든 Thread에서만 Valid하다.
- Local reference를 다른 Thread로 전달해서는 안된다. 다른 Thread에서 이 Local reference를 Share하고 싶은 경우에는 반드시 Global reference 로 만들어 Share해야 한다.
참조 포인터 제거
FindClass, NewCharArray, 등으로 획득한 jobject 관련 객체는 사용 후 반드시 DeleteLocalRef 함수로 참조를 제거해야 한다.
JIN_OnLoad
- JNI 도움말 | Android NDK | Android Developers
- JNI와 NDK (5) JNI 네이티브 함수 직접 등록하기
- NDK(4) - JNI_OnLoad 예제, 한글처리 :: Programming
#include <jni.h>
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env;
if (vm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
// env 포인터를 사용하여 Java 메서드 호출 등의 작업을 수행합니다.
return JNI_VERSION_1_6;
}
The Java™ Native Interface: Programmer’s Guide and Specification
- ORACLE: Java Native Interface Specification—Contents
- The Java™ Native Interface - Programmer’s Guide and Specification 2
JNI Functions
JNI로 AttachCurrentThread가 -1이 리턴되는 경우
- JNI로 AttachCurrentThread가 -1이 리턴되는 경우
-
http://docs.hp.com/en/JDKJRE60RN/jdk_rnotes_6.0.01.html#CreateJavaVM -
http://docs.hp.com/en/JAVAPROGUIDE/JNI_java2.html
Native Library에서 pthread로 생성된 쓰레드를 자바에서 사용하려면(예를 들어 Callback 함수를 사용한다던가), JNI함수에서 AttachCurrentThread를 이용하여 JNIEnv를 가져와야 하는데, 이걸 가져오지 못하고, -1이 리턴되는 경우가 있습니다. 원인을 살펴보던 중 pthread로 생성될때 기본 스택 크기가 256k였고, 이 크기가 문제가 되는 것 같습니다. pthread_attr_setstacksize()를 이용해서 스택크기를 500k이상으로 주니, 함수가 정상적으로 동작하네요.
생성된 Thread 내에서의 JNIEnv::FindClass가 동작하지 않는다
Android JNI 에서, pthread_create 에 의해 생성된 스레드 내에서 JNIEnv::FindClass 메소드가 항상 실패하고 만다. 구글링해본 결과 정확한 해결책은 찾지 못했고 얻은 힌트에 의해면 해당하는 Class 의 ClassLoader 를 설정해줘야 한다고 한다. (SEE System.setClassLoader) JNIEnv 개체는 Thread Local 값이기 때문에 전역으로 공유해서는 안된다. native 스레드에서 JNI 로 JavaClass 를 호출하려면 JavaVM 의 AttachCurrentThread 나 AttachCurrentThreadAsDaemon 메소드를 통해 JAVA 의 MainThread 그룹에 등록해줘야 한다. 그런데 그렇게 해도 위의 클래스 로더문제 때문에 JNIEnv::FindClass 를 이용해주려면 클래스로더를 등록하던가 아예 초기화 과정(JNI_OnLoad 나 별도의 초기화 Routine)에서 해당하는 클래스의 레퍼런스를 아예 미리 캐시하고 있는 것이 낫다. 그런데 FindClass 에서 얻은 jclass reference 는 LocalReference 이므로 다음과 같이 JNIEnv::NewGlobalRef 를 통해 Global Reference 로 캐시해야 한다.
jclass g_myClass; // 전역에서 정의
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
// ... (중략)
g_myClass = reinterpret_cast<jclass>(myEnv->NewGlobalRef(myClass));
Favorite site
- Wikipedia (en) JNI에 대한 설명
- [추천] JNI에서 콜백함수 구현하기
- [추천] 안드로이드 JNI 콜백 호출 기법 3
- [추천] JNI_OnLoad를 이용한 Java Native Interface 정의 방법 (RegisterNatives를 사용한 방법)
- JAVA Native Method (JNI) 4
- JNI Tutorial - String과 Array 사용 5
- JNI 사용방법6
- Java Native Interface 사양의 목차 7
- JNI 동작원리 개념(NewGlobalRef) 8
- JNI C/C++ 코드에서 JAVA메서드 호출하기 9
- JNI Invocation API
References
-
Java_additional_jni_features.pdf ↩
-
JNI_Programmer’s_Guide_and_Specification.pdf ↩
-
How_to_use_JNI_Callback.pdf ↩
-
JAVA_Native_Method_(JNI).pdf ↩
-
JNI_Tutorial_-_String,_Array.pdf ↩
-
How_to_use_JNI.pdf ↩
-
Eureka7_com_ne_kr.zip (eureka7.com.ne.kr/jdk-1_5_0-Korean-doc/docs/guide/jni/spec/jniTOC.html 참조) ↩
-
Principle_of_operation_JNI.pdf ↩
-
How_to_use_JNI_Callback.pdf ↩