No JNI_OnLoad 문제 해결

4615 단어
오보 문제는 다음과 같습니다.
04-29 13:53:12.184: D/dalvikvm(361): Trying to load lib/data/data/com.conowen.helloworld/lib/libHelloWorld.so 0x44edea98 04-29 13:53:12.204: D/dalvikvm(361): Added shared lib/data/data/com.conowen.helloworld/lib/libHelloWorld.so 0x44edea98
04-29 13:53:12.204: D/dalvikvm(361): No JNI_OnLoad found in/data/data/com.conowen.helloworld/lib/libHelloWorld.so 0x44edea98, skipping init
원리 설명:
Android의 응용층의 클래스는 모두 자바로 작성된 것입니다. 자바 클래스는Dex 파일로 컴파일된 후에 Dalvik 가상기기 (Virtual Machine) 에 의해 실행되어야 합니다.C&C++의 함수는 Dalvik 가상 기기에서 실행되는 것이 아니기 때문에 효율과 속도는 Dalvik 가상 기기에서 실행되는 것보다 훨씬 빠르다.만약 자바 프로그램을 실행할 때 C & C++ 함수를 불러와야 한다면, 불러오는 것은 어떤 과정입니까?
1. 자바는 Dalvik 가상 머신에게 로컬 C/C++ 라이브러리를 불러오라고 알립니다. 호출 함수: System.loadLibrary("Name");
2. Dalvik 가상 머신이 성공적으로 라이브러리를 불러오면 자동으로 라이브러리 안의 JNI를 찾습니다OnLoad 함수 - 로컬 메서드는 JNIOnLoad 함수, 일부 버전에서는 이 함수를 실현할 필요가 없습니다. 불러올 때 시스템의 기본 JNI 를 호출할 수 있습니다.OnLoad 함수.그러니까 만약에 라이브러리에 JNI가 안 적혀있다면...OnLoad() 함수는 VM에서 가장 오래된 JNI 1.1 버전을 기본적으로 사용합니다.그러나 새 버전의 JNI는 많은 확충을 했고 일부 내용도 최적화시켰다. JNI의 새 버전 기능을 사용해야 한다면 반드시 JNIOnLoad() 함수는 JNI 버전을 선언합니다.
(1) Dalvik VM 이 C 라이브러리에서 사용하는 JNI 버전을 알려줍니다.JNI가 없으면...OnLoad () 함수와 새로 확장된 jni 함수를 호출하면 Android 디버그 정보는 다음과 같습니다 (No JNI OnLoad found).
#include
#define LOG    "TEST-L" // LOG   
#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG,__VA_ARGS__) //  LOGD   
#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG,__VA_ARGS__) //  LOGI   
#define LOGW(...)  __android_log_print(ANDROID_LOG_WARN,LOG,__VA_ARGS__) //  LOGW   
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG,__VA_ARGS__) //  LOGE   
#define LOGF(...)  __android_log_print(ANDROID_LOG_FATAL,LOG,__VA_ARGS__) //  LOGF 
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {  
    JNIEnv* env = NULL;
    jint result = -1;  
	
    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {  
        LOGE("jni_load failed
"); return result; } result = JNI_VERSION_1_4; return result; }

(2) Dalvik 가상 머신이 C 라이브러리를 불러올 때 첫 번째 일은 JNI 를 호출하는 것이기 때문이다OnLoad () 함수, 그래서 우리는 JNIOnLoad () 에서 JNI 함수 등록 등 초기화 작업을 진행합니다.로컬 함수를 등록하면 자바층이 로컬 함수를 호출하는 효율을 높일 수 있지만 이런 방법은android 원본에서 컴파일하는 데만 적응할 수 있다.다음은 C++ 버전의 로드 함수입니다.
jint JNI_OnLoad(JavaVM* vm, void* reserved) {  
    JNIEnv* env = NULL;// JNI Env  
    jint result = -1;  
    /*JavaVM::GetEnv   jint (*GetEnv)(JavaVM*, void**, jint);   
     */  
    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {  
        LOGE(ANDROID_LOG_ERROR, TAG, "GetEnv failed!");  
        return result;  
    }  
  
    LOGI(ANDROID_LOG_INFO, TAG, "loading . . .");  
  
/*  
 *  JNI env 
 *  register_android_test_myclass_myffunc(env)  
 */  
      
    if(register_android_test_myclass_myffunc(env) != JNI_OK) {  
        LOGE(ANDROID_LOG_ERROR, TAG, 
		"can't load register_android_test_myclass_myffunc");  
        goto end;  
    }  
  
    LOGI(ANDROID_LOG_INFO, TAG, "loaded");  
  
    result = JNI_VERSION_1_4;  
  
    return result;  
}  
static const char* const kClassPathName = "com/test/myclass"; 

static JNINativeMethod gMethods[] = {  
    {"setParam",       "(Ljava/lang/String;)V",        (void *)com_test_myclass_setParam},  
    {"prepare",             "()V",                     (void *)com_test_myclass_prepare},  
};

int register_android_test_myclass_myffunc(JNIEnv *env) {  
    return jniRegisterNativeMethods(env, kClassPathName, gMethods, 
			sizeof(gMethods) / sizeof(gMethods[0]));  
    /* OnLoad.cpp  
     * jint jniRegisterNativeMethods(JNIEnv* env, 
                             const char* className, 
                             const JNINativeMethod* gMethods, 
                             int numMethods) 
                              
     */  
}

참고:
여기서 AndroidRuntime::registerNativeMethods는 헤더 파일androidruntime/AndroidRuntime.h에서 정의, 사용 시
안드로이드에 있어야 돼.mk 파일에 더하기:
LOCAL_SHARED_LIBRARIES += \
         libandroid_runtime 
GetEnv () 함수가 반환되는 Jni 환경은 스레드마다 다릅니다.
Dalvik 가상 머신은 대개 Multi-threading이기 때문이다.스레드당 JNI 호출OnLoad() 시
사용하는 JNI Env는 다르므로 함수에 들어갈 때마다 vm->GetEnv를 통해 다시 가져와야 합니다.
 
(3) 및 JNIOnLoad() 함수에 해당하는 함수 JNIOnUnload(), VM이 C 라이브러리를 해제하면 JNI 호출OnUnload() 함수로 클린업 작업을 수행합니다.
/*
 * , 
 * , 
 * 
 */
void JNI_OnUnload(JavaVM* vm, void* reserved){  
     LOGI("call JNI_OnUnload ~~!!");
} 

좋은 웹페이지 즐겨찾기