Dalvik虚拟机JNI方法的注册过程分析 (七)

2014-11-24 10:58:08 · 作者: · 浏览: 4
oad(JavaVM* vm, void* reserved); 函数dvmLoadNativeCode通过调用函数dlsym就可以获得在前面加载的so中名称为“JNI_OnLoad”的函数的地址,最终保存在函数指针func中。有了这个函数指针之后,我们就可以直接调用它来执行注册JNI方法的操作了。注意,在调用该JNI_OnLoad函数时,第一个要传递进行的参数是一个JavaVM对象,这个JavaVM对象描述的是在当前进程中运行的Dalvik虚拟机,第二个要传递的参数可以设置为NULL,这是保留给以后使用的。


从前面Dalvik虚拟机的启动过程分析一文可以知道,在当前进程所运行的Dalvik虚拟机实例是通过全局变量gDvm所描述的一个DvmGlobals结构体的成员变量vmList来描述的,因此,我们就可以将它传递在前面加载的so中名称中定义的JNI_OnLoad函数。注意,定义在该so文件中的JNI_OnLoad函数一旦执行成功,它的返回值就必须等于JNI_VERSION_1_2、JNI_VERSION_1_4或者JNI_VERSION_1_6,用来表示所注册的JNI方法的版本。

最后, 函数dvmLoadNativeCode根据上述的JNI_OnLoad函数的执行成功与否,将前面所创建的一个SharedLib对象pNewEntry的成员变量onLoadResult设置为kOnLoadOkay或者kOnLoadFailed,这样就可以记录参数pathName所指定的so文件是否是加载成功的,也就是它是否成功地注册了其内部的JNI方法。

在我们这个情景中,参数pathName所指定的so文件为libnanosleep.so,接下来我们就继续分析它的函数JNI_OnLoad的实现,以便可以发解定义在它里面的JNI方法的注册过程。

Step 5. JNI_OnLoad

定义在libnanosleep.so文件中的函数JNI_OnLoad的实现可以参考文章开始的部分。从它的实现可以知道,它所注册的JNI方法shy_luo_jni_ClassWithJni_nanosleep是与shy.luo.jni.ClassWithJni类的成员函数nanosleep对应的,并且是通过调用函数jniRegisterNativeMethods来实现的。因此,接下来我们就继续分析函数jniRegisterNativeMethods的实现。

Step 6. jniRegisterNativeMethods


[cpp] int jniRegisterNativeMethods(JNIEnv* env, const char* className,
const JNINativeMethod* gMethods, int numMethods)
{
jclass clazz;

LOGV("Registering %s natives\n", className);
clazz = (*env)->FindClass(env, className);
if (clazz == NULL) {
LOGE("Native registration unable to find class '%s'\n", className);
return -1;
}

int result = 0;
if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
LOGE("RegisterNatives failed for '%s'\n", className);
result = -1;
}

(*env)->DeleteLocalRef(env, clazz);
return result;
}

int jniRegisterNativeMethods(JNIEnv* env, const char* className,
const JNINativeMethod* gMethods, int numMethods)
{
jclass clazz;

LOGV("Registering %s natives\n", className);
clazz = (*env)->FindClass(env, className);
if (clazz == NULL) {
LOGE("Native registration unable to find class '%s'\n", className);
return -1;
}

int result = 0;
if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
LOGE("RegisterNatives failed for '%s'\n", className);
result = -1;
}

(*env)->DeleteLocalRef(env, clazz);
return result;
} 这个函数定义在文件dalvik/libnativehelper/JNIHelp.c中。

参数env所指向的一个JNIEnv结构体,通过调用这个JNIEnv结构体可以获得参数className所描述的一个类。这个类就是要注册JNI的类,而它所要注册的JNI就是由参数gMethods来描述的。

注册参数gMethods所描述的JNI方法是通过调用env所指向的一个JNIEnv结构体的成员函数RegisterNatives来实现的,因此,接下来我们就继续分析它的实现。

Step 7. JNIEnv.RegisterNatives


[cpp] typedef _JNIEnv JNIEnv;
......

struct _JNIEnv {
/* do not rename this; it does not seem to be entirely opaque */
const struct JNINativeInterface* functions;
......

jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,
jint nMethods)
{ return functions->RegisterNatives(this, clazz, methods, nMethods); }

......
}

typedef _JNIEnv JNIEnv;
......

struct _JNIEnv {
/* do not rename this; it does not seem to be entirely opaque */
const struct JNINativeInterface* functions;
......

jint RegisterNatives(jclass clazz, const JNINativeMethod* metho