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

Calling System.loadLibrary twice for the same shared library

本文关键字:System loadLibrary 两次 调用 共享      更新时间:2023-10-16

我遇到了两个jar库使用同一个共享库的情况。在每个库中,"主接口"类加载带有System.loadLibrary的.so文件。我的问题是:如果用户决定在一个项目中使用这两个jar库,那么对同一.so文件的System.loadLibrary的第二次调用会引起任何异常吗?还是系统"如何处理"以防止共享库被加载两次?或者可能有一种"众所周知的模式"来处理这种情况?

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

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

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

如果您运行的是清单中有android:sharedUserId="android.uid.system"的Android系统应用程序,或者预装到设备上,或者使用平台证书签名,并且您试图调用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将重新启动。