我有一个为 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/