终于建了一个自己个人小站:https://huangtianyu.gitee.io,以后优先更新小站博客,欢迎进站,O(∩_∩)O~~
JNI_OnLoad是在加载so的时候调用的,也就是System.loadLibrary("test")时候调用的。具体调用步骤如下:
System.loadLibrary(libName)->Runtime.loadLibrary(libName,classLoader)->Runtime.doLoad(libName,loader)->Runtime.nativeLoad(name,loader,ldLibraryPath)->JavaVMExt.loadNativieLibrary:(JavaVMExt* vm=Runtime::Current()->GetJavaVM(); vm->LoadNativieLibrary(filename,classloader,detail))->jni_internal.cc::LoadNativieLibrary->dlopen,dlsym->JNI_OnLoad。
以上给出了调用顺序,具体代码可以根据类名或方法名看出。有兴趣的可以自己查看下源码。
在Runtime.loadLibrary中,会在多个多个路径下寻找对应的so,只要找到了就会去加载,加载成功就会返回。对应代码如下:
Runtime.java
/*
* Searches for and loads the given shared library using the given ClassLoader.
*/
void loadLibrary(String libraryName, ClassLoader loader) {
if (loader != null) {
String filename = loader.findLibrary(libraryName);
if (filename == null) {
// It's not necessarily true that the ClassLoader used
// System.mapLibraryName, but the default setup does, and it's
// misleading to say we didn't find "libMyLibrary.so" when we
// actually searched for "liblibMyLibrary.so.so".
throw new UnsatisfiedLinkError(loader + " couldn't find \"" +
System.mapLibraryName(libraryName) + "\"");
}
String error = doLoad(filename, loader);
if (error != null) {
throw new UnsatisfiedLinkError(error);
}
return;
}
String filename = System.mapLibraryName(libraryName);
List<String> candidates = new ArrayList<String>();
String lastError = null;
for (String directory : mLibPaths) {
String candidate = directory + filename;
candidates.add(candidate);
if (IoUtils.canOpenReadOnly(candidate)) {
String error = doLoad(candidate, loader);
if (error == null) {
return; // We successfully loaded the library. Job done.
}
lastError = error;
}
}
if (lastError != null) {
throw new UnsatisfiedLinkError(lastError);
}
throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
}
mLibPaths初始化代码如下:
/**
* Holds the library paths, used for native library lookup.
*/
private final String[] mLibPaths = initLibPaths();
private static String[] initLibPaths() {
String javaLibraryPath = System.getProperty("java.library.path");
if (javaLibraryPath == null) {
return EmptyArray.STRING;
}
String[] paths = javaLibraryPath.split(":");
// Add a '/' to the end of each directory so we don't have to do it every time.
for (int i = 0; i < paths.length; ++i) {
if (!paths[i].endsWith("/")) {
paths[i] += "/";
}
}
return paths;
}