我遇到两个jar库使用相同共享库的情况。
在每个库中,“主界面”类使用System.loadLibrary
加载.so文件。
我的问题是:如果用户决定在一个项目中使用这两个jar库,第二次调用同一个.so文件的System.loadLibrary
会导致任何异常吗?或者系统“以某种方式处理”以防止共享库被加载两次?或者也许有一种“众所周知的模式”来处理这种情况?
jni包装器的目标是在android上使用。我是两个包装器库的作者,所以回答你可以完全控制java源代码。
答案 0 :(得分:17)
根据apidocs,它应该不是问题:“如果使用相同的库名称多次调用此方法,则忽略第二次和后续调用。”
答案 1 :(得分:7)
我发现一个非常狭窄的用例,这将是一个问题。
如果您运行的是Android系统应用,清单中的android:sharedUserId="android.uid.system"
已预装到设备或signed with the platform certificate,并且您尝试拨打System.loadLibrary
两次以加载相同的库(通过运行相同的应用程序两次,或创建两个单独的系统应用程序加载相同的库),Android将重新启动。
从这个库中调用JNI方法(如果尚未加载),在android.uid.system
进程内运行时不会产生异常,就像普通的Android应用程序一样 - 它将重启Android。
为了防止这种情况,并查明库是否已加载,您可以阅读文件/proc/self/maps
并在那里搜索您的库名称。 ClassLoader
并且反射在这里没有帮助 - 即使尚未加载库,它们也会将JNI方法显示为可访问。
请注意,您无法执行if (Runtime.getRuntime().exec("/system/bin/grep <library-name> /proc/self/maps").waitFor() == 0)
- 禁止系统进程通过SELinux启动任何外部命令,您必须从Java代码中读取该文件。
另一个怪癖是必须将库预安装到/system/lib
目录的设备 - 如果您将库与应用程序捆绑在一起,并将应用程序安装到设备,库将最终在/data/app/..../lib
,当你尝试从/data
分区加载它时,你已经猜到了 - Android会重启。