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

2014-11-24 10:58:08 · 作者: · 浏览: 2
{
.......
result = false;
} else {
LOGV("+++ finished JNI_OnLoad %s\n", pathName);
}

}

......

if (result)
pNewEntry->onLoadResult = kOnLoadOkay;
else
pNewEntry->onLoadResult = kOnLoadFailed;

......

return result;
}
}

bool dvmLoadNativeCode(const char* pathName, Object* classLoader,
char** detail)
{
SharedLib* pEntry;
void* handle;
......

pEntry = findSharedLibEntry(pathName);
if (pEntry != NULL) {
if (pEntry->classLoader != classLoader) {
......
return false;
}
......

if (!checkOnLoadResult(pEntry))
return false;
return true;
}
......

handle = dlopen(pathName, RTLD_LAZY);
......

/* create a new entry */
SharedLib* pNewEntry;
pNewEntry = (SharedLib*) calloc(1, sizeof(SharedLib));
pNewEntry->pathName = strdup(pathName);
pNewEntry->handle = handle;
pNewEntry->classLoader = classLoader;
......

/* try to add it to the list */
SharedLib* pActualEntry = addSharedLibEntry(pNewEntry);

if (pNewEntry != pActualEntry) {
......
freeSharedLibEntry(pNewEntry);
return checkOnLoadResult(pActualEntry);
} else {
......

bool result = true;
void* vonLoad;
int version;

vonLoad = dlsym(handle, "JNI_OnLoad");
if (vonLoad == NULL) {
LOGD("No JNI_OnLoad found in %s %p, skipping init\n",
pathName, classLoader);
} else {
......

OnLoadFunc func = vonLoad;
......

version = (*func)(gDvm.vmList, NULL);
......

if (version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4 &&
version != JNI_VERSION_1_6)
{
.......
result = false;
} else {
LOGV("+++ finished JNI_OnLoad %s\n", pathName);
}

}

......

if (result)
pNewEntry->onLoadResult = kOnLoadOkay;
else
pNewEntry->onLoadResult = kOnLoadFailed;

......

return result;
}
} 这个函数定义在文件dalvik/vm/Native.c中。

函数dvmLoadNativeCode首先是检查参数pathName所指定的so文件是否已经加载过了,这是通过调用函数findSharedLibEntry来实现的。如果已经加载过,那么就可以获得一个SharedLib对象pEntry。这个SharedLib对象pEntry描述了有关参数pathName所指定的so文件的加载信息,例如,上次用来加载它的类加载器和上次的加载结果。如果上次用来加载它的类加载器不等于当前所使用的类加载器,或者上次没有加载成功,那么函数dvmLoadNativeCode就回直接返回false给调用者,表示不能在当前进程中加载参数pathName所描述的so文件。


我们假设参数pathName所指定的so文件还没有被加载过,这时候函数dvmLoadNativeCode就会先调用dlopen来在当前进程中加载它,并且将获得的句柄保存在变量handle中,接着再创建一个SharedLib对象pNewEntry来描述它的加载信息。这个SharedLib对象pNewEntry还会通过函数addSharedLibEntry被缓存起来,以便可以知道当前进程都加载了哪些so文件。

注意,在调用函数addSharedLibEntry来缓存新创建的SharedLib对象pNewEntry的时候,如果得到的返回值pActualEntry指向的不是SharedLib对象pNewEntry,那么就表示另外一个线程也正在加载参数pathName所指定的so文件,并且比当前线程提前加载完成。在这种情况下,函数addSharedLibEntry就什么也不用做而直接返回了。否则的话,函数addSharedLibEntry就要继续负责调用前面所加载的so文件中的一个指定的函数来注册它里面的JNI方法。

这个指定的函数的名称为“JNI_OnLoad”,也就是说,每一个用来实现JNI方法的so文件都应该定义有一个名称为“JNI_OnLoad”的函数,并且这个函数的原型为:


[cpp] jint JNI_OnLoad(JavaVM* vm, void* reserved);

jint JNI_OnL