/ ClassLoader#findLibrary() /
findLibrary() 将到 ClassLoader 中查找 lib,取决于各 JVM 的具体实现 。比如可以看看 Android 上的实现 。
- 到 DexPathList 的具体实现中调用
- 首先通过 System 类的 mapLibraryName() 中获得 mapping 后的 lib 全名,细节见下章节
- 遍历存放 native lib 路径元素数组 nativeLibraryPathElements
- 逐个调用各元素的 findNativeLibrary() 实现去寻找
- 一经找到立即返回,遍历结束仍未发现的话返回 null
// android/libcore/dalvik/src/main/java/dalvik/system/// BaseDexClassLoader.javapublic String findLibrary(String name) {return pathList.findLibrary(name);}// android/libcore/dalvik/src/main/java/dalvik/system/// DexPathList.javapublic String findLibrary(String libraryName) {// 到 System 中获得 mapping 后的 lib 全名String fileName = System.mapLibraryName(libraryName);// 到存放 native lib 路径数组中遍历for (NativeLibraryElement element : nativeLibraryPathElements) {String path = element.findNativeLibrary(fileName);// 一旦找到立即返回并结束,反之进入下一次循环if (path != null) {return path;}}// 路径中全找遍了,仍未找到则返回 nullreturn null;} System#mapLibraryName()
mapLibraryName() 的作用很简单,即将 lib 名称 mapping 到完整格式的名称,比如输入 opencv 得到的是 libopencv.so 。如果遇到名称为空或者长度超上限 240 的话,将抛出相应 Exception 。
// java/lang/System.javapublic static native String mapLibraryName(String libname); 其是 native 方法,具体实现位于 JDK Native Source Code 中,可在如下网站中看到,网站地址如下:
http://hg.openjdk.java.NET/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/native
// native/java/lang/System.c#define JNI_LIB_PREFIX "lib"#define JNI_LIB_SUFFIX ".so"Java_java_lang_System_mapLibraryName(JNIEnv *env, jclass ign, jstring libname){// 定义最后名称的 Sring 长度变量int len;// 并获取 lib 前缀、后缀的字符串常量的长度int prefix_len = (int) strlen(JNI_LIB_PREFIX);int suffix_len = (int) strlen(JNI_LIB_SUFFIX);// 定义临时的存放最后名称的 char 数组jchar chars[256];// 如果 libname 参数为空,抛出 NPEif (libname == NULL) {JNU_ThrowNullPointerException(env, 0);return NULL;}// 获取 libname 长度len = (*env)->GetStringLength(env, libname);// 如果大于 240 的话抛出 IllegalArgumentExceptionif (len > 240) {JNU_ThrowIllegalArgumentException(env, "name too long");return NULL;}// 将前缀 ”lib“ 的字符拷贝到临时的 char 数组头部cpchars(chars, JNI_LIB_PREFIX, prefix_len);// 将 lib 名称从字符串里拷贝到 char 数组的 “lib” 后面(*env)->GetStringRegion(env, libname, 0, len, chars + prefix_len);// 更新名称长度为:前缀+ lib 名称len += prefix_len;// 将后缀 ”.so“ 的字符拷贝到临时的 char 数组里的 lib 名称后cpchars(chars + len, JNI_LIB_SUFFIX, suffix_len);// 再次更新名称长度为:前缀+ lib 名称 + 后缀len += suffix_len;// 从 char 数组里提取当前长度的复数 char 成员到新创建的 String 对象中返回return (*env)->NewString(env, chars, len);}static void cpchars(jchar *dst, char *src, int n){int i;for (i = 0; i < n; i++) {dst[i] = src[i];}} 逻辑很清晰,检查 lib 名称参数是否合法,之后便是将名称分别加上前后缀到临时字符数组中,最后转为字符串返回 。
nativeLibraryPathElements()
nativeLibraryPathElements 数组来源于获取到的所有 native Library 目录后转换而来 。
// android/libcore/dalvik/src/main/java/dalvik/system/// DexPathList.javapublic DexPathList(ClassLoader definingContext, String librarySearchPath) {...this.nativeLibraryPathElements = makePathElements(getAllNativeLibraryDirectories());} 所有 native Library 目录除了包含应用自身的 library 目录列表以外,还包括了系统的列表部分 。
// android/libcore/dalvik/src/main/java/dalvik/system/// DexPathList.javaprivate List<File> getAllNativeLibraryDirectories() {List<File> allNativeLibraryDirectories = new ArrayList<>(nativeLibraryDirectories);allNativeLibraryDirectories.addAll(systemNativeLibraryDirectories);return allNativeLibraryDirectories;}/** List of application native library directories. */private final List<File> nativeLibraryDirectories;/** List of system native library directories. */private final List<File> systemNativeLibraryDirectories; 应用自身的 library 目录列表来自于 DexPathList 初始化时传入的 librarySearchPath 参数,splitPaths() 负责去该 path 下遍历各级目录得到对应数组 。
推荐阅读
- 一篇讲明白DevOps时代下的持续架构实践
- HTTP缓存看这一篇就够了
- |紫砂壶不挂水就不是好壶吗?
- 天津市|职场人的仕途,无非就是这三个阶段
- 2月逛花市,就选四种漂亮花,浇点水就能活,花开一整年
- 5种花一晒就蔫,放暗处越长越绿,养不好都是弄反了
- 市场营销专业就业方向怎么样,最新市场营销专业当前的就业形势分析
- |老婆打疫苗非要穿露肩连衣裙,戴着口罩就不怕丢脸了吗?
- 出口营销策划方案怎么做,未来出口营销就业前景
- 贺兰山|自己一知半解,却嘲讽壮壮没文化。那就说说《满江红》的贺兰山吧
