jaehwa

jaehwa.egloos.com

포토로그



JNI 네이티브 함수에 직접등록방법 (간단한 예제 - 전체 동작 원리를 알 수 있는 예제) 안드로이드 JNI & NDK


우선 아래 소스는 안드로이드 전체 소스에서 볼 수 있는 소스코드이다.

샘플 이름데로JNI관련해서 기본적인 구조를 알 수 있는데 도움이 될 것이다.

 

소스 경로: development/samples/SimpleJNI

 SimpleJNI.zip

위 소스에 있는 소스를NDK에서 빌드 및 실행이 되도록 수정을 하여 만들어 보았다. (간단하게 몇몇 부분만 수정하면NDK에서도 사용할 수 있었다.)

샘플의 소스는 문서와 같이 첨부한SimpleJNI.zip 파일을 참고하기 바란다.

 

소스의 핵심적인 부분과 설명은 하자면 다음과 같다.

 

SimpleJNI.java

package com.example.android.simplejni;

import android.app.Activity;

import android.os.Bundle;

import android.widget.TextView;

 

public class SimpleJNI extends Activity {

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        TextView tv = new TextView(this);

        int sum = Native.add(2, 3);

        tv.setText("2 + 3 = " + Integer.toString(sum));

        setContentView(tv);

    }

}

 

class Native {

    static {

        System.loadLibrary("simplejni");

    }

 

    static native int add(int a, int b);

}

 

1) libsimplejni.so 라이브러리를 로딩한다.

2) 사용할 네이티브 메서드 add 를 선언한다.

 

Java 소스는 위에서 설명한 '기본적인 JNI 사용' 에서와 차이는 없다. 차이점은 다음의 네이티브(C++)소스에서 차이가 있다.

 

native.cpp

#define LOG_TAG "simplejni native.cpp"

#include "log.h"

#include <stdio.h>

#include "jni.h"

 

//(3) JNI에서 사용하는 실제 네이티브 함수

static jint

add(JNIEnv *env, jobject thiz, jint a, jint b) {

int result = a + b;

    LOGI("%d + %d = %d", a, b, result);

    return result;

}

 

//(5) 네이티브 함수를 사용할 자바 클래스

static const char *classPathName = "com/example/android/simplejni/Native";

 

//(2) jni.h 에서 제공하는 JNINativeMethod 구조체 배열로 사용할 JNI 메서드를 정리

static JNINativeMethod methods[] = {

  {"add", "(II)I", (void*)add },

};

 

static int registerNativeMethods(JNIEnv* env, const char* className,

    JNINativeMethod* gMethods, int numMethods)

{

    jclass clazz;

    clazz = env->FindClass(className);

    if (clazz == NULL) {

        LOGE("Native registration unable to find class '%s'", className);

        return JNI_FALSE;

    }

   //(4) methods[] 에서 나열한 JNI 메서드를 실제 함수 등록을 하는 과정이다.

    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {

        LOGE("RegisterNatives failed for '%s'", className);

        return JNI_FALSE;

    }

 

    return JNI_TRUE;

}

 

 

static int registerNatives(JNIEnv* env)

{

  if (!registerNativeMethods(env, classPathName,

                 methods, sizeof(methods) / sizeof(methods[0]))) {

    return JNI_FALSE;

  }

 

  return JNI_TRUE;

}

 

typedef union {

    JNIEnv* env;

    void* venv;

} UnionJNIEnvToVoid;

 

//(1) 라이브러리 로딩시 호출

jint JNI_OnLoad(JavaVM* vm, void* reserved)

{

    UnionJNIEnvToVoid uenv;

    uenv.venv = NULL;

    jint result = -1;

    JNIEnv* env = NULL;

   

    LOGI("JNI_OnLoad");

 

    if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {

        LOGE("ERROR: GetEnv failed");

        goto bail;

    }

    env = uenv.env;

 

    if (registerNatives(env) != JNI_TRUE) {

        LOGE("ERROR: registerNatives failed");

        goto bail;

    }

   

    result = JNI_VERSION_1_4;

   

bail:

    return result;

}

 

 

1) JNI_OnLoad 함수는 Java 에서 라이브러리를 로드하는 시점에서 호출된다. (1)

JNI_OnLoad() 의 기본적인 기능은 자바 가상 머신이 지원하는 JNI 버전을 확인하는 것이다. 그러므로 JNI_OnLoad 메서드에서는 JNI 버전정보를 반드시 반환해야한다.

또한 JNI_OnLoad() 에서 자바 가상 머신이 네이티브 라이브러리를 로드할때 JNI에 대한 초기화 작업을 할 수 있다.

자세히 봐야 할 부분은 JNI_OnLoad 에서 registerNatives 함수를 호출한다.

 

2) registerNatives 함수안에서 registerNativeMethods 함수를 호출하여 JNI 네이티브 함수를 등록한다.

위 소스에서 JNI  네이티브 함수 등록을 위해서 아래의 배열을 만든다. (2)

static JNINativeMethod methods[] = {

  {"add", "(II)I", (void*)add },

};

자바에서 첫번째 파라메터의 api 이름으로 사용하게 되며 파라메터와 리턴값은 II(I) 로 알 수 있다. 두개의 정수 값의 파라메터를 가지고 리턴값이 정수값임을 알 수있다.

자바에서 사용하는 add 함수의 구현은 (void*) add 에 구현되어 있다. (3)

 

여기서 핵심은 jni.h에 정의된 JNINativeMethod 구조체를 사용하여 등록한다는 것이다.

typedef struct {

           const char* name;                    //JNI 함수이름

           const char* signature;             //JNI 함수의 파라미터와 반환 값

           void* fntPtr;                            //JNI 함수의 네이티브 함수 포인터

} JNINativeMethod;

 

 

3) registerNativeMethods 함수안에서 JNI에서 제공하는 메서드 RegisterNatives 를 사용하여 실제 사용할 함수를 등록한다.

네이티브 함수를 사용할 자바 클래스는 변수 classPathName 에 지정하였다. (5)

위에서 설명한 “1. 일반적인 JNI 사용방법“2. JNI 네이티브 함수에 직접등록방법의 샘플을 비교했을때, 첫번째 방법의 경우에는 간단하게 사용할 수 있는 장점이 보이고 두번째 방법의 경우 사용하는 네이티브 메서드가 많을 경우 Class이름을 바꾸기가 쉬워보인다.

 

위 두 방법의 핵심적인 차이는 http://jaehwa.egloos.com/1029760 에서 설명한다.


덧글

  • 학생 2010/11/20 00:41 # 삭제 답글

    JNINativeMethod 구조체를 사용하여 등록할 때, 파라미터 반환값이나 함수 포인터에 관련된 리스트나 테이블 자료는 어디서 찾을 수 있을까요~
댓글 입력 영역



애드센스 광고

애드센스 광고(링크단위)