1.告诉VM此C组件使用那一个JNI版本。如果你的*.so档没有提供JNI_On
2.由于VM执行到System.loadLibrary()函数时,就会立即先呼叫JNI_On
例如,在Android的/system/lib/libmedia_jni.so档案里,就提供了JNI_On
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaPlayer-JNI"
………
jint JNI_On
{
JNIEnv* env = NULL;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGE("ERROR: GetEnv failed\n");
goto bail;
}
assert(env != NULL);
if (register_android_media_MediaPlayer(env) < 0) {
LOGE("ERROR: MediaPlayer native registration failed\n");
goto bail;
}
if (register_android_media_MediaRecorder(env) < 0) {
LOGE("ERROR: MediaRecorder native registration failed\n");
goto bail;
}
if (register_android_media_MediaScanner(env) < 0) {
LOGE("ERROR: MediaScanner native registration failed\n");
goto bail;
}
if (register_android_media_MediaMetadataRetriever(env) < 0) {
LOGE("ERROR: MediaMetadataRetriever native registration failed\n");
goto bail;
}
/* success -- return valid version number */
result = JNI_VERSION_1_4;
bail:
return result;
}
// KTHXBYE
此函数回传JNI_VERSION_1_4值给VM,于是VM知道了其所使用的JNI版本了。此外,它也做了一些初期的动作(可呼叫任何本地函数),例如指令:
if (register_android_media_MediaPlayer(env) < 0) {
LOGE("ERROR: MediaPlayer native registration failed\n");
goto bail;
}
就将此组件提供的各个本地函数(Native Function)登记到VM里,以便能加快后续呼叫本地函数之效率。
JNI_On
jint JNI_On
{
………
}
jint JNI_On
{
………
}
在JNI_On
jint JNI_On
{
JNIEnv* env = NULL;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGE("ERROR: GetEnv failed\n");
goto bail;
}
由于VM通常是多执行绪(Multi-threading)的执行环境。每一个执行绪在呼叫JNI_On
jint JNI_On
{
JNIEnv* env = NULL;
……….
if (register_android_media_MediaPlayer(env) < 0) {
…….
}
}
这JNI_On
例如,在register_android_media_MediaPlayer()函数里,可撰写下述指令:
if ((*env)->MonitorEnter(env, obj) != JNI_OK) {
………
}
查看是否已经有其他执行绪进入此物件,如果没有,此执行绪就进入该物件里执行了。还有,也可撰写下述指令:
if ((*env)->MonitorExit(env, obj) != JNI_OK) {
………
}
查看是否此执行绪正在此物件内执行,如果是,此执行绪就会立即离开。
PS:从上面这篇文章可以看出,其实Android中的so文件就像是Windows下的DLL一样,JNI_On