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

2022-09-02 23:45:54

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

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


答案 1

根据 apidocs 的说法,这应该不是问题:“如果使用相同的库名称多次调用此方法,则将忽略第二次和后续调用。


答案 2

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

如果您运行的是具有清单的 Android 系统应用,或者预装到设备上,或者使用平台证书进行签名,并且您尝试调用两次来加载同一个库(通过运行同一应用两次,或者创建两个单独的系统应用来加载同一个库),Android 将重新启动。android:sharedUserId="android.uid.system"System.loadLibrary

从这个库中调用JNI方法,如果它还没有加载,在进程内运行时不会生成异常,就像普通的Android应用程序一样 - 它会重新启动Android。android.uid.system

为了防止这种情况,并找出库是否已加载,您可以读取文件并在那里搜索您的库名称。 反射在这里没有帮助 - 即使尚未加载库,它们也会将JNI方法显示为可访问。/proc/self/mapsClassLoader

请注意,你不能这样做 - 系统进程被禁止通过SELinux启动任何外部命令,你必须从Java代码中读取文件。if (Runtime.getRuntime().exec("/system/bin/grep <library-name> /proc/self/maps").waitFor() == 0)

另一个怪癖是,库必须预先安装到设备到目录 - 如果您将库与应用程序捆绑在一起,然后将应用程序安装到设备,则库将最终进入,当您尝试从分区加载它时,您已经猜到了 - Android将重新启动。/system/lib/data/app/..../lib/data


推荐