09-JavaVM与JNIEnv

JavaVM与JNIEnv

JNI中其他类型:成员域ID和方法ID

//成员域ID、成员方法ID:
struct _jfieldID;
typedef struct _jfieldID* jfield;

struct _jmethodID;
typedef _jmethodID* jemthodID

jvalue : 可以代表不同类型的变量,注意jboolean和jlong

typedef union jvalue {
    jboolean    z;
    jbyte       b;
    jchar       c;
    jshort      s;
    jint        i;
    jlong       j;
    jfloat      f;
    jdouble     d;
    jobject     l;
} jvalue;

JNI_Onload

JNI_Onload是有共享库导出的,有用户来实现。

执行时机:在一个so被加载时调用

/* Prototypes for functions exported by loadable shared libs.  These are called by JNI, not provided by JNI. */
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved);//第二个参数是保留的
JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved);

JavaVM和JNIEnv

struct _JNIEnv;
struct _JavaVM;
typedef const struct JNINativeInterface* C_JNIEnv;

#if defined(__cplusplus)
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;
#endif
jnienv在C和cpp中的使用:使用C很繁琐,用CPP比较简洁
// C中
jclass TestJclass = (*env)->FindClass(env,"com/showme/reflectiontest/Test");
jfieldID publicStaticField_jfieldID = (*env)->GetStaticFieldID(env,TestJclass, "publicStaticField","Ljava/lang/String;");
jstring publicStaticField_content = (jstring) (*env)->GetStaticObjectField(env,TestJclass,publicStaticField_jfieldID);
const char *content_ptr = (*env)->GetStringUTFChars(env,publicStaticField_content, NULL);
__android_log_print(4, "showme->jni", "jni->%s", content_ptr);


// cpp中
jclass TestJclass = env->FindClass("com/showme/reflectiontest/Test");
jfieldID publicStaticField_jfieldID = env->GetStaticFieldID(TestJclass, "publicStaticField","Ljava/lang/String;");
jstring publicStaticField_content = (jstring) env->GetStaticObjectField(TestJclass,publicStaticField_jfieldID);
const char *content_ptr = env->GetStringUTFChars(publicStaticField_content, nullptr);
__android_log_print(4, "showme->jni", "jni->%s", content_ptr);
JavaVM

JavaVM是虚拟机在JNI层的代表,一个进程只有一个JavaVM,所有的线程共用一个JavaVM

  • JNIInvokeInterface_结构封装和JVM相关的功能函数,如销毁JVM,获得当前线程Java执行环境
  • 在C和C++中JavaVM的定义有所不同,在C中JavaVM是JNIInvokeInterface_类型指针,而在C++中又对JNIInvokeInterface_进行了一次封装
  • 推荐用C++来编写JNI代码,比C中少了一个参数
JNIEnv

JNIEnv表示Java调用native语言的环境,是一个封装了大量JNI方法的指针

JNIENv只在创建它的线程中生效,不能跨线程传递,不同线程的JNIENv彼此独立

native环境中创建的线程,如果需要访问JNI,必须要调用AttachCurrentThread关联,并使用DetachCurrentThread解除链接

JavaVM的获取

1、在JNI_Onload中作为参数获得,如下:

JNIEXPORT jint JNICALL JNI_Onload(JavaVM* vm,void* reserved),该函数由ART负责自动化查找和传入参数进行调用

2、通过JNIEnv的GetJavaVM函数获取,如下:

JavaVM* thisvjm = nullptr;

env->GetJavaVM(&thisjvm);

native创建的新线程,需要在线程中使用线程自身的JNIEnv

// c创建新线程
pthread_t thread;
pthread_create(&thread, nullptr, threadtest, nullptr);
pthread_join(thread, nullptr);


// 新线程,需要获取自身的JNIEnv,并附加到JavaVM(这个JNIEnv需要知道自身从属于哪个虚拟机)
void *threadtest(void *args) {
  JNIEnv *threadenv = nullptr;
  if (globalVM->GetEnv((void **) &threadenv, JNI_VERSION_1_6) == JNI_OK);
  
  int result = globalVM->AttachCurrentThread(&threadenv, nullptr);//重要
  
	if (result == JNI_OK);

  threadenv->ExceptionDescribe();//打印异常
	threadenv->ExceptionClear();//清除异常
  
  globalVM->DetachCurrentThread();//重要
  
	pthread_exit(0);
}

注意事项-这个真的很重要

  • JNIEnv是与一个ClassLoader绑定的,当使用env->FindClass()进行类的查询和加载时便是使用的这个ClassLoader(在主线程中可以)
  • JNIEnv是当前Java线程的执行环境,一个JVM对应一个JavaVM结构,而一个JVM中可能创建多个Java线程,使用pthread_create新建的线程当使用AttachCurrentThread(&env,NULL)获取到JNIEnv后,该JNIEnv的ClassLoader并不是主线程的ClassLoader,因此也就无法加载app自己的Class (解决方式是:1、主线程在启动子线程时,将ClassLoader当做参数传递,2、在主线程中创建全局的ClassLoader)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值