安卓构建系统如何处理加载本地共享库的Java库?

3
考虑以下情况:我有两个名为P1和P2的Android项目,它们都生成一个apk,使用相同的进程ID并在Android上运行在同一进程中。P1和P2都使用Java库JL1。JL1在运行时加载共享库1 SL1。
我在运行时看到的是,在某些时候,我会得到一个java/lang/UnsatisfiedLinkError,同时输出:Shared lib already opened。
这个问题的原因是什么?我认为在Java中的库代码在每个项目/apk中都被复制了,当apk在一个进程中合并时,它忘记了这些副本。因此,每个副本都会自己加载其共享库,导致已经加载的错误。
如果是这样,这不是我们想要的行为。因为现在你永远不能在同一进程中使用带有共享库的Java库超过一次。
[编辑]我发现每个apk都使用自己的类加载器(即使在同一进程中)。这意味着每个JL将被每个apk加载,并且因此每个共享对象将被加载多次,导致错误。有人有什么想法如何解决这个问题吗?是否可能让apk共享类加载器?

看起来你的P1和P2是由不同的类加载器加载的。你能确认一下吗?如果确实是这种情况,据我所知,这是预期的行为,即:“相同的JNI本地库不能加载到多个类加载器中。” http://docs.oracle.com/javase/1.4.2/docs/guide/jni/jni-12.html 一个解决方法是设计你的类,使得只有一个集合需要访问本地方法... - Samuel Audet
我认为我必须找出来。我不知道安卓如何处理这个问题。我认为你是对的,正如问题所解释的那样。我使用两个不同的apk文件,它们被加载到同一个进程中。我可以想象安卓会为每个apk实例化一个类加载器。如果为每个进程创建一个类加载器会更好。我必须查一下安卓是如何处理这个问题的。 - Bjorn
我查了一下。每个apk都有自己的类加载器。这意味着共享对象将被加载两次。有什么解决方法吗? - Bjorn
我将以我的答案作为结论,并在StackOverflow上发布另一个帖子,包含有关类加载器细节的信息。 - Bjorn
抱歉回复晚了...好的,如果这回答了你的问题,太好了!我猜 :) - Samuel Audet
1个回答

1
每个apk都有自己的类加载器。这意味着两个项目/apk将拥有库中类的自己的副本,它们在运行时加载。因此,看起来相同的类实际上是副本。因此,在这样的类中加载本地库将导致为每个加载的类加载它(即使在静态字段中执行此操作)。如果两个apk共享同一进程,则会导致运行时错误,因为加载本机共享对象超过一次。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接