为同一共享库调用System.loadLibrary两次

时间:2014-02-19 10:05:25

标签: java android c++ java-native-interface

我遇到两个jar库使用相同共享库的情况。 在每个库中,“主界面”类使用System.loadLibrary加载.so文件。 我的问题是:如果用户决定在一个项目中使用这两个jar库,第二次调用同一个.so文件的System.loadLibrary会导致任何异常吗?或者系统“以某种方式处理”以防止共享库被加载两次?或者也许有一种“众所周知的模式”来处理这种情况?

jni包装器的目标是在android上使用。我是两个包装器库的作者,所以回答你可以完全控制java源代码。

2 个答案:

答案 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会重启。