출처: http://blog.naver.com/brighteyes79/130149049628
JNI를 통한 안드로이드라이브러리에서 자바 함수 호출 기법
JNI(JavaNative Interface)에서는 managed 코드 (Java) 에서 Native 코드(C/C++)와 상호 작용을 하는
방법을 제공해준다.
이것은 벤더 중립적으로 동적 공유 라이브러리를로딩하여 사용할 수 있도록 하는 것이다. 안드로이드에서는 Java 언어로개발된 애플리케이션과 프레임워크에서 Native 에 있는 라이브러리를 호출하여 사용하기 위하여 JNI를 사용한다.
그리고 콜백을 수행하는 기법이라고 알려진 Native 코드에서 Java 메서드를 호출하는 기법이 JNI 에서 제공된다.
JNI 콜백기법은 기본적으로 안드로이드의 Bluetooth, 카메라, 미디어플레이어 등 에서 커널 단으로부터
발생되는 이벤트들을 Native 단에서 Java 프레임워크로 올려줄 때 사용되며, 물론 사용자 라이브러리에서 Async 한 처리를 하고 난 후 결과를 어플리케이션에 알리고자 할 때 유용하게 사용된다.
자바 프레임워크에서 콜백을 받은 경우는 브로드캐스트를 통하여 안드로이드에 해당 이벤트를 알려주고,
사용자 어플리케이션의 경우에는 콜백에 따른 결과를 UI 에 표시하는등 활용하면 되겠다.
Java 프로그래밍언어에는 몇가지 메서드 유형이 있는데 Static 메서드는 어떠한 인스턴스에 독립적으로
호출하는 반면, 인스턴스 메서드는 클래스의 특정 인스턴스를 호출해야한다.
JNI 는 Native 코드에서콜백을 수행할 수 있도록 기능들을 제공한다. 아래의 예제는native 코드가 Java로
구현된 인스턴스 메서드를 호출하도록 한다.
class InstanceMethodCall { private native void nativeMethod(); System.out.println("In Java"); public static void main(String args[]) { InstanceMethodCall c = new InstanceMethodCall(); |
아래는 native 코드의 구현부이다.
이 프로그램을 실행하면 다음과 같이 나온다.
In C In Java |
● 인스턴스메서드 호출
Native 에서는 주어진 클래스에서 해당 메서드를 찾기 위해 GetMethod 함수를 호출한다.
이 때 메서드를 찾기 위해 메서드의이름과 타입 기술자를 살펴본다. 만약 해당 메서드가 존재하지 않으면null 을 리턴한다.
그 다음으로는 CallVoidMethod 함수를 호출한다. 이 함수는 리턴 형이 void 인 인스턴스 함수를 호출한다. 만일 int 형이면CallIntMethod, String 이나 배열 같은 객체를 리턴하는 경우에는CallobjectMethod 를
사용한다.
만약 인터페이스 메서드를 호출하고자하면 함수의 <Type>Methodfamily 를 호출해야한다.
예를 들어서com.mdsedu.test.JniTestLib 의 myMethod() 라는 void 함수를 호출하고자 하는 경우에는
다음과 같이 한다.
jmethodID mid; jclass Intf = (*env)->FindClass(env, "com/mdsedu/test/JniTestLib"); if (Intf == NULL) { ... /* error handling */ } mid = (*env)->GetMethodID(env, Intf, "myMethod", "()V"); if (mid == NULL) { ... /* error handling */ } (*env)->CallVoidMethod(env, Intf, mid); ... /* check for possible exceptions */ |
● JNITypes 와 Data Structures
JNI에서 Java 타입과 Native 타입을 매핑할 때 Primitive Type 의 경우다음의 테이블과 같이 사용한다.
Java Type |
||
Type Signature
JNI는 Type Signature 라고하는 java VM 의 표기법을 사용한다.
Type Signature |
|
예를 들어, Java 함수가 아래와 같다면
Long f (int n, String s, int[] arr); |
다음과 같은 type signature 를 갖는다.
(ILjava/lang/String;[I)J |
● Static메서드 호출
Native 코드로부터 static 메서드를다음과 같이 호출할 수 있다.
GetStaticMethodId 로 메서드아이디를 취득한 후 CallStaticVoidMethod 에 클래스,메서드 아이디,
static 메서드의 family 중하나를 넘기며 해당 함수를 호출한다.
다음은 native 코드로부터 static 메서드를콜백으로 호출하는 예제이다.
class StaticMethodCall { private native void nativeMethod(); private static void callback() { System.out.println("In Java"); } public static void main(String args[]) { StaticMethodCall c = new StaticMethodCall(); c.nativeMethod(); } static { System.loadLibrary("StaticMethodCall"); } } |
아래는 native 호출 구현이다.
JNIEXPORT void JNICALL Java_StaticMethodCall_nativeMethod(JNIEnv *env, jobject obj) { jclass cls = (*env)->GetObjectClass(env, obj); jmethodID mid = (*env)->GetStaticMethodID(env, cls, "callback", "()V"); if (mid == NULL) { return; /* method not found */ } printf("In C\n"); (*env)->CallStaticVoidMethod(env, cls, mid); } |
Q/A
# 메서드 아이디를 얻을때 String 타입 파라미터 하나에String 리턴 타입인 Java 함수를
호출하기 위해서 네 번째 인자인 signature를 어떻게 지정 해야하는가 ?
위에서 설명한 TypeSignature 표기법에 따라 (Ljava/lnag/String)java/lang/String
# Native 단에서스레드를 사용하면서 JNI 콜백 함수를 호출할 수 있는가 ?
Native의 쓰레드는 커널에 의해 스케줄링 되는 리눅스 스레드인데, 일반적으로 managed 코드에서
시작하지만 어디든 생성된 후 Java VM 에 attach 된다.예를 들어서 스레드는 pthread_create 에서
생성되고 JNI AttachCurrentThread 로 attach된다. 스레드는 attach 될 때까지 JNIEnv가 없고
JNI 콜을 할 수 없다.
안드로이드는 Native 코드를 실행하는 스레드를 서스팬드시키지 않는다.
가비지 콜렉터가 진행중이거나 디버거가 서스팬드 요청을 하는 경우에는 안드로이드가 일시 중지를
시킨다.
Attach된 스레드가 종료하기 전에JNI는 DetachCurrentThread 를 호출해야한다.
if (pthread_create(&thread, NULL, &work_thread, (void *)data) < 0) { … static void *work_thread(void *arg) { JNIEnv* env; if (jvm->AttachCurrentThread(&env, NULL) != JNI_OK) { … if (jvm->DetachCurrentThread() != JNI_OK) { return NULL; }
|
'IT_Programming > Android_Java' 카테고리의 다른 글
[펌] RESTful Java client with Apache HttpClient (0) | 2014.04.09 |
---|---|
[펌] 안드로이드/Android HttpUrlConnection Request 설명 및 설정 하기 (header, get, post, body등.) (0) | 2014.04.08 |
[안드로이드] 웹뷰(WebView) 멈춤 현상 (0) | 2014.03.28 |
안드로이드 정의 속성으로 커스텀 뷰 만들기 (0) | 2014.03.27 |
[펌] AsyncTask와 Activity or Fragment (0) | 2014.03.25 |