原标题:一文深入理解 JNI实现机制
写在前面
说到JNI都不陌生,它的全称:Java Native Interface,即Java本地接口。
JNI不仅仅是Android特有的,它是属于Java平台的,它允许在Java虚拟机内运行的java代码与其他编程语言(如c, c++和汇编语言)编写的程序和库进行交互。
JNI调用姿势:Java —> JNI —> C/C++(SO库)
在Android平台中,使用JNI封装了跟硬件相关的操作,从而可以通过Java调用相关JNI模块,以达到对硬件的调用。
下面我们将围绕如下内容进行展开:
1.java代码编译和执行过程
2.jni常规使用姿势
3.so加载流程(jni执行流程、注册方式原理)
4.JNIEnv作用及实现
Java代码编译和执行过程
java代码编译和执行的过程涉及到两个命令:javac和java
1.首先通过javac编译java代码,生成class字节码文件
2.javacTestCode.java --> TestCode.class
3.然后通过java命令来执行class字节码
4.javaTestCode.class
java命令执行过程中,会先启动虚拟机,加载TestCode类信息到内存,然后由执行引擎执行其main方法。
JVM的逻辑内存模型如下:
JNI常规使用姿势
在java层通过native关键字创建本地方法,如下:(成员方法、static方法)
public
classJNIMethods{
static{
System.loadLibrary( "test-jni");
}
//隐式注册
publicnativeString stringFromJNI();
publicstaticnativeString testParams(intjint, String jstring, Object jobject, Object[] arrayObject, Listlist);
//显式注册
publicnativeString stringFromJNIDis();
publicstaticnativeString testParamsDis(intjint, String jstring, Object jobject, Object[] arrayObject, Listlist);
}
创建c层代码,并注册本地方法
#include
#include
#include"common.h"
jstring stringFromJNIDis(JNIEnv *env, jobject jobj);
jstring testParamsDis(JNIEnv *env, jclass type, jint jint_, jstring jstring_, jobject jobject_, jobjectArray objectArray, jobject list);
staticjmethodID methodID_toString;
//显式注册
staticJNINativeMethod gMethods[] = {
{ "stringFromJNIDis", "()Ljava/lang/String;", ( void*) stringFromJNIDis},
{ "testParamsDis", "(ILjava/lang/String;Ljava/lang/Object;[Ljava/lang/Object;Ljava/util/List;)Ljava/lang/String;", ( void*) testParamsDis}
};
staticintregisterNativeMethods(JNIEnv *env, constchar*className, JNINativeMethod *methods, intnMethods){
jclass clazz;
clazz = env->FindClass(className);
if(clazz == NULL) {
returnJNI_FALSE;
}
if(env->RegisterNatives(clazz, methods, nMethods) < 0) {
returnJNI_FALSE;
}
returnJNI_TRUE;
}
voidappendString(JNIEnv *env, char*dest, jstring tmpStr){
if(tmpStr == NULL) {
return;
}
constchar*tmpString = env->GetStringUTFChars(tmpStr, 0);
strcat(dest, tmpString);
env->ReleaseStringUTFChars(tmpStr, tmpString);
}
//加载so时会执行该方法
JNIEXPORT jint JNICALL JNI_(JavaVM *vm, void*reserved){
LOGD( "test-jni.cpp JNI_");
JNIEnv *env = NULL;
if(vm->GetEnv(( void**) &env, JNI_VERSION_1_4) != JNI_OK) {
return-1;
}
if( NULL== env) {
return-1;
}
jclass clazz = env->FindClass( "java/lang/Object");
methodID_toString = env->GetMethodID(clazz, "toString", "()Ljava/lang/String;");
//显式注册本地方法
if(!registerNativeMethods(env, "com/mob/test/jni/testjni/JNIMethods", gMethods, NELEM(gMethods))) {
LOGE( "test-jni.cpp JNI_ register JNIMethods failed");
}
returnJNI_VERSION_1_4;
}
//卸载时会执行该方法
JNIEXPORT voidJNI_OnUnload(JavaVM *vm, void*reserved){
LOGD( "test-jni.cpp JNI_OnUnload");
methodID_toString = NULL;
}
//隐式注册
extern"C"JNIEXPORT jstring JNICALL
Java_com_mob_test_jni_testjni_JNIMethods_stringFromJNI(JNIEnv *env, jobject jobj){
LOGD( "test-jni.cpp Java_com_mob_test_jni_testjni_JNIMethods_stringFromJNI");
returnstringFromJNIDis(env, jobj);
}
extern"C"JNIEXPORT jstring JNICALL
Java_com_mob_test_jni_testjni_JNIMethods_testParams(JNIEnv *env, jclass type, jint jint_, jstring jstring_, jobject jobject_,
jobjectArray arrayObject,
jobject list){
LOGD( "test-jni.cpp Java_com_mob_test_jni_testjni_JNIMethods_testParams");
returntestParamsDis(env, type, jint_, jstring_, jobject_, arrayObject, list);
}
//显式注册
jstring stringFromJNIDis(JNIEnv *env, jobject jobj){
LOGD( "test-jni.cpp stringFromJNIDis");
std:: stringhello = "Hello from C++";
returnenv->NewStringUTF(hello.c_str());
}
jstring testParamsDis(JNIEnv *env, jclass type, jint jint_, jstring jstring_, jobject jobject_, jobjectArray arrayObject, jobject list){
LOGD( "test-jni.cpp testParamsDis");
charreturnValue[ 1024];
inti = jint_;
sprintf(returnValue, "%d", i);
appendString(env, returnValue, jstring_);
jstring returnToString = reinterpret_cast<_jstring>(env->CallObjectMethod(jobject_, methodID_toString));
appendString(env, returnValue, returnToString);
jsize len = env->GetArrayLength(arrayObject);
jobject tmpObject;
jstring tmpString;
for(i = 0; i < len; i++) {
tmpObject = env->GetObjectArrayElement(arrayObject, i);
tmpString = reinterpret_cast<_jstring>(env->CallObjectMethod(tmpObject, methodID_toString));
appendString(env, returnValue, tmpString);
}
env->DeleteLocalRef(tmpObject);
jclass clazz_list = env->GetObjectClass( list);
jmethodID list_get = env->GetMethodID(clazz_list, "get", "(I)Ljava/lang/Object;");
jmethodID list_size = env->GetMethodID(clazz_list, "size", "()I");
intsize = env->CallIntMethod( list, list_size);
jstring itemStr;
for(i = 0; i < size; i++) {
itemStr = reinterpret_cast(env->CallObjectMethod( list, list_get, i));
appendString(env, returnValue, itemS