System.loadLibrary() 和 System.load() 的区别

Android 开发也好,java 开发也好,都会有遇到过加载 so 库的情况

加载 so 库有两个方法:System.loadLibrary() 和 System.load(),它们有什么区别呢?


package java.lang;

public final class System {

    // ....

    @CallerSensitive
    public static void load(String filename) {
        Runtime.getRuntime().load0(Reflection.getCallerClass(), filename);
    }

    @CallerSensitive
    public static void loadLibrary(String libname) {
        Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname);
    }

    // ....
}

可以看到都是由 Runtime 这个类去做的,但是在 Android Studio 是看不到的,隐藏了,这时候就需要去看系统源码了:http://androidxref.com/9.0.0_r3/xref/libcore/ojluni/src/main/java/java/lang/Runtime.java


 System.loadLibrary():

package java.lang;

public class Runtime {

    @CallerSensitive
    public void loadLibrary(String libname) {
        loadLibrary0(VMStack.getCallingClassLoader(), libname); // 拿 classLoader 继续执行逻辑
    }

    synchronized void loadLibrary0(ClassLoader loader, String libname) {
        if (libname.indexOf((int)File.separatorChar) != -1) { // 反斜杠 "\" 符号判断
            throw new UnsatisfiedLinkError("Directory separator should not appear in library name: " + libname);
        }
        String libraryName = libname;
        if (loader != null) {
            String filename = loader.findLibrary(libraryName); // 找 so 库
            if (filename == null) {
                throw new UnsatisfiedLinkError(loader + " couldn't find \"" + System.mapLibraryName(libraryName) + "\"");
            }

            String error = nativeLoad(filename, loader); // 真正加载 so 库的底层函数
            if (error != null) { // 加载失败
                throw new UnsatisfiedLinkError(error);
            }
            return;
        }

        // ....
    }
}

可以看到是调用了 classLoader 的 findLibrary() 找到 so 库的路径后传给底层函数进行加载,而这个 classLoader 是 BaseDexClassLoader:

package dalvik.system;

public class BaseDexClassLoader extends ClassLoader {

    // ...

    private final DexPathList pathList;

    @Override
    public String findLibrary(String name) {
        return pathList.findLibrary(name);
    }

    // ...
}

又跳到了 DexPathList 的 findLibrary():

package dalvik.system;

final class DexPathList {
    // ...

    private final List<File> nativeLibraryDirectories; // so 文件集合

    public String findLibrary(String libraryName) {
        String fileName = System.mapLibraryName(libraryName);

        for (NativeLibraryElement element : nativeLibraryPathElements) {
            String path = element.findNativeLibrary(fileName); // 找 so 库

            if (path != null) {
                return path;
            }
        }
        return null;
    }

    static class NativeLibraryElement {

        public String findNativeLibrary(String name) {
            // ...

            String entryPath = new File(path, name).getPath();
            if (IoUtils.canOpenReadOnly(entryPath)) { // 可以打开 so 库(也就是存在这个so)
                return entryPath;
            }

            // ...
            return null;
        }
    }
}

这里描述的是如何去查找是否存在 so 的,就是能否通过 io 流去打开这个 so 路径,若能打开,则说明存在


System.load():

package java.lang;

public class Runtime {
    // ...

    synchronized void load0(Class<?> fromClass, String filename) {
        if (!(new File(filename).isAbsolute())) {
            throw new UnsatisfiedLinkError(
                "Expecting an absolute path of the library: " + filename);
        }
        if (filename == null) {
            throw new NullPointerException("filename == null");
        }
        String error = nativeLoad(filename, fromClass.getClassLoader()); // 真正加载 so 库的底层函数
        if (error != null) { // 加载失败
            throw new UnsatisfiedLinkError(error);
        }
    }

    // ...
}

非常直接,因为传进来的是 so 文件路径,所以直接传给底层函数去加载 so


总结:

System.loadLibrary(String libName) 先把传进来的 so 库名拿去查找对应的路径,查找到 so 文件路径进行加载

System.load(String libPath) 根据传进来的 so 文件路径进行加载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值