java - 动态加载/重新加载 Java 类时防止重复调用 System.loadLibrary

标签 java android java-native-interface

我有一个为 Android 系统维护的插件系统。正在加载的插件之一在静态初始化 block 中调用 System.loadLibrary()

一个插件是这样加载的:

Class<?> pluginClass = Class.forName(clsName, true, classLoader);

第一次调用时,一切正常。

如果插件因任何特定原因(禁用/启用或更重要的是版本升级)而重新加载,它会尝试重新初始化该类,我会收到如下所示的错误:

2019-01-11 17:10:30.160 30764-31064/com.foobar W/PluginInstanceManager: Couldn't load plugin: com.foobar.plugin
    java.lang.UnsatisfiedLinkError: Shared library "/data/app/com.foobar.plugin-eVVPC94W5JcpK0yF00OfHw==/lib/arm64/liblibrary-jni.so" already opened by ClassLoader 0x187(dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.foobar.plugin-eVVPC94W5JcpK0yF00OfHw==/base.apk"],nativeLibraryDirectories=[/data/app/com.foobar.plugin-eVVPC94W5JcpK0yF00OfHw==/lib/arm64, /data/app/com.foobar.plugin-eVVPC94W5JcpK0yF00OfHw==/base.apk!/lib/arm64-v8a, /system/lib64, /vendor/lib64, /system/product/lib64, /system/lib64, /vendor/lib64, /system/product/lib64]]]); can't open in ClassLoader 0x735fd03f9c(dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.foobar.plugin-eVVPC94W5JcpK0yF00OfHw==/base.apk"],nativeLibraryDirectories=[/data/app/com.foobar.plugin-eVVPC94W5JcpK0yF00OfHw==/lib/arm64, /data/app/com.foobar.plugin-eVVPC94W5JcpK0yF00OfHw==/base.apk!/lib/arm64-v8a, /system/lib64, /vendor/lib64, /system/product/lib64, /system/lib64, /vendor/lib64, /system/product/lib64]]])
        at java.lang.Runtime.loadLibrary0(Runtime.java:1048)
        at java.lang.Runtime.loadLibrary0(Runtime.java:1007)
        at java.lang.System.loadLibrary(System.java:1669)
        at com.foobar.plugin.<clinit>(FoobarPlugin.java:31)
...

它似乎在提示那个库已经被加载,因此我无法再次加载该类。

有没有办法卸载类/库?有没有办法检查库是否已经加载?

最佳答案

Runtime.loadLibrary() 应该忽略同一库的后续加载,根据 method javadoc :

If this method is called more than once with the same library name, the second and subsequent calls are ignored.

可能插件卸载未完成,看起来 ClassLoader 0x187 从以前的插件生命周期中幸存下来。最好检查一下这个 ClassLoader 对象实例是什么。

你可以试试ClassLoader.findLibrary()并且只有在得到 null 时才尝试加载库:

Returns the absolute path name of a native library. The VM invokes this method to locate the native libraries that belong to classes loaded with this class loader. If this method returns null, the VM searches the library along the path specified as the "java.library.path" property.

关于java - 动态加载/重新加载 Java 类时防止重复调用 System.loadLibrary,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54155086/

相关文章:

java - JdbcTemplate映射器空值

java - 计算 MergeSort Java 的比较次数

接收器的 Android 别名

java - JNI_CreateJavaVM 退出代码 -1?

java - 使用反射查找 JNI 中的 Java 类是否为 Final

java - HTML 表单发布与 PHP 表单发布

java - 全局引用 findViewById

java - fragment 中的Onclick按钮方法

java - Android - 存储对 ApplicationContext 的引用

java - ubuntu 14.04 上的 JNI4Net