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

Tom*_*wel 8 c++ java java-native-interface android

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

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

van*_*kel 17

根据apidocs它应该不是一个问题:"如果使用相同的库名称多次调用此方法,则忽略第二次和后续调用."

  • 为了帮助那些可能正在寻找"幂等"这个词的未来人们,就是这样. (5认同)

pel*_*lya 7

我发现一个非常狭窄的用例,这将是一个问题.

如果您正在运行Android系统应用程序,android:sharedUserId="android.uid.system"在清单中,要么预先安装到设备,要么使用平台证书进行签名,并且您尝试调用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会重启.