// android/libcore/dalvik/src/main/java/dalvik/system/// DexPathList.javapublic DexPathList(ClassLoader definingContext, String librarySearchPath) {...this.nativeLibraryDirectories = splitPaths(librarySearchPath, false);}private static List<File> splitPaths(String searchPath, boolean directoriesOnly) {List<File> result = new ArrayList<>();if (searchPath != null) {for (String path : searchPath.split(File.pathSeparator)) {if (directoriesOnly) {try {StructStat sb = Libcore.os.stat(path);if (!S_ISDIR(sb.st_mode)) {continue;}} catch (ErrnoException ignored) {continue;}}result.add(new File(path));}}return result;}
系统列表则来自于系统的 path 路径,调用 splitPaths() 的第二个参数不同,促使其在分割的时候只处理目录类型的部分,纯文件的话跳过 。
// android/libcore/dalvik/src/main/java/dalvik/system/// DexPathList.javapublic DexPathList(ClassLoader definingContext, String librarySearchPath) {...this.systemNativeLibraryDirectories =splitPaths(System.getProperty("java.library.path"), true);...}
拿到 path 文件列表之后就是调用 makePathElements 转成对应元素数组 。
- 按照列表长度创建等长的 Element 数组
- 遍历 path 列表
- 如果 path 包含 "!/" 的话,将其拆分为 path 和 zipDir 两部分,并创建 NativeLibraryElement 实例
- 反之如果是目录的话,直接用 path 创建 NativeLibraryElement 实例,zipDir 参数则为空
// android/libcore/dalvik/src/main/java/dalvik/system/// DexPathList.javaprivate static NativeLibraryElement[] makePathElements(List<File> files) {NativeLibraryElement[] elements = new NativeLibraryElement[files.size()];int elementsPos = 0;for (File file : files) {String path = file.getPath();if (path.contains(zipSeparator)) {String split[] = path.split(zipSeparator, 2);File zip = new File(split[0]);String dir = split[1];elements[elementsPos++] = new NativeLibraryElement(zip, dir);} else if (file.isDirectory()) {// We support directories for looking up native libraries.elements[elementsPos++] = new NativeLibraryElement(file);}}if (elementsPos != elements.length) {elements = Arrays.copyOf(elements, elementsPos);}return elements;} findNativeLibrary()
findNativeLibrary() 将先确保当 zip 目录存在的情况下内部处理 zip 的 ClassPathURLStreamHandler 实例执行了创建 。
- 如果 zip 目录不存在(一般情况下都是不存在的)直接判断该路径下 lib 文件是否可读,YES 则返回 path/name、反之返回 null
- zip 目录存在并且 ClassPathURLStreamHandler 实例也创建完毕的话,检查该 name 的 zip 文件的存在 。并在 YES 的情况下,在 path 和 name 之间跟上 zip 目录并返回,即:path/!/zipDir/name
// DexPathList.java// android/.../libcore/dalvik/src/main/java/dalvik/system/DexPathList.javaprivate static final String zipSeparator = "!/";static class NativeLibraryElement {public String findNativeLibrary(String name) {// 确保 element 初始化完成maybeInit();if (zipDir == null) {// 如果 zip 目录为空,则直接创建该 path 下该文件的 File 实例// 可读的话则返回String entryPath = new File(path, name).getPath();if (IoUtils.canOpenReadOnly(entryPath)) {return entryPath;}} else if (urlHandler != null) {// zip 目录并且 urlHandler 都存在// 创建该 zip 目录下 lib 文件的完整名称String entryName = zipDir + '/' + name;// 如果该名称的压缩包是否存在的话if (urlHandler.isEntryStored(entryName)) {// 返回:路径/zip目录/lib 名称的结果出去return path.getPath() + zipSeparator + entryName;}}return null;}// 主要是确保在 zipDir 不为空的情况下// 内部处理 zip 的 urlHandler 实例已经创建完毕public synchronized void maybeInit() {...}} / ClassLoader#loadLibrary0() /
1.调用静态内部类 NativeLibrary 的 native 方法 findBuiltinLib() 检查是否是内置的动态链接库,细节见如下章节 。如果不是内置的 library,通过 AccessController 检查该 library 文件是否存在 。
- 不存在则加载失败并结束
- 存在则到本 ClassLoader 已加载 library 的 nativeLibraries Vector 或系统 class 的已加载 library Vector systemNativeLibraries 中查找是否加载过
- 已加载过则结束
- 反之继续加载的任务
2.到所有 ClassLoader 已加载过的 library Vector loadedLibraryNames 里再次检查是否加载过,如果不存在的话,抛出 UnsatisfiedLinkError:
Native Library xxx already loaded in another classloader
推荐阅读
- 一篇讲明白DevOps时代下的持续架构实践
- HTTP缓存看这一篇就够了
- |紫砂壶不挂水就不是好壶吗?
- 天津市|职场人的仕途,无非就是这三个阶段
- 2月逛花市,就选四种漂亮花,浇点水就能活,花开一整年
- 5种花一晒就蔫,放暗处越长越绿,养不好都是弄反了
- 市场营销专业就业方向怎么样,最新市场营销专业当前的就业形势分析
- |老婆打疫苗非要穿露肩连衣裙,戴着口罩就不怕丢脸了吗?
- 出口营销策划方案怎么做,未来出口营销就业前景
- 贺兰山|自己一知半解,却嘲讽壮壮没文化。那就说说《满江红》的贺兰山吧
