我有一个为Android系统维护的插件系统。正在加载的其中一个插件在静态初始化块中调用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)
...
似乎在抱怨该库已经被加载,因此我无法再次加载该类。
是否有一种方法可以卸载课程/库?有没有办法检查库是否已经加载?
答案 0 :(得分:0)
Runtime.loadLibrary()
应该忽略method javadoc中相同库的后续加载:
如果使用相同的库名称多次调用此方法,则第二次及以后的调用将被忽略。
可能是该插件的卸载尚未完成,看起来ClassLoader 0x187
在以前的插件生命周期中仍然存在。检查一下这个ClassLoader
对象实例是什么。
您可以尝试ClassLoader.findLibrary()
并仅在获得null
时尝试加载库:
返回本机库的绝对路径名。 VM调用此方法来查找属于使用此类加载器加载的类的本机库。如果此方法返回
null
,则VM沿指定为"java.library.path"
属性的路径搜索库。
答案 1 :(得分:0)
来自edit
:
每个类加载器都管理自己的一组本机库。同一JNI本机库不能被加载到多个类加载器中。这样做会引发UnsatisfiedLinkError。例如,System.loadLibrary在用于将本机库加载到两个类加载器中时抛出UnsatisfiedLinkError。
要在两个插件或同一个插件的两个实例中使用本机库,必须确保已将其装入某些共享的类加载器中。