Android L Preview不在“中搜索本机库”;armeabi“;文件夹(未满足链接错误)

Android L Preview不在“中搜索本机库”;armeabi“;文件夹(未满足链接错误),android,android-ndk,android-5.0-lollipop,Android,Android Ndk,Android 5.0 Lollipop,我有一个带有2个本机库的应用程序。第1个版本在ARMv7上运行得更快,所以我有适用于ARMv7和ARMv5的版本。第二个在两种平台上的工作原理相同,因此只提供了ARMv5库 我的本机库文件夹如下所示: /jniLibs/ | +---armeabi/ | | | +---libFirstLibrary.so | +---libSecondLibrary.so | +---armeabi-v7a/

我有一个带有2个本机库的应用程序。第1个版本在ARMv7上运行得更快,所以我有适用于ARMv7和ARMv5的版本。第二个在两种平台上的工作原理相同,因此只提供了ARMv5库

我的本机库文件夹如下所示:

/jniLibs/
    |
    +---armeabi/
    |     |
    |     +---libFirstLibrary.so
    |     +---libSecondLibrary.so
    |
    +---armeabi-v7a/
          |
          +---libFirstLibrary.so
lib/armeabi/libgello-jni.so
lib/armeabi/libhello-jni.so
lib/armeabi/libhello-jni2.so
lib/armeabi/libtello-jni.so
lib/armeabi-v7a/libhello-jni.so
该应用程序在生产中的所有设备和Android版本上都运行良好

当我在Nexus 5上用L-Preview(hammerhead-lpv79-Preview-ac1d8a8e.tgz)测试它时,我得到以下错误:

java.lang.UnsatisfiedLinkError: Couldn't load SecondLibrary from loader dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.package-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.package-1, /vendor/lib, /system/lib]]]: findLibrary returned null
   at java.lang.Runtime.loadLibrary(Runtime.java:358)
   at java.lang.System.loadLibrary(System.java:610)
问题是,尽管Nexus 5将
CPU_ABI
设置为
armeabi-v7a
并将
CPU_ABI2
设置为
armeabi
,但L-Preview只使用
CPU_ABI
值,只在“armeabi-v7a”文件夹中查找“SecondLibrary”,并在不存在时崩溃

当我将.so文件也复制到“armeabi-v7a”文件夹时,一切都很好,但APK比它大3.5MB,我不太喜欢


这仅仅是安卓L-Preview的一个bug还是一些“新功能”?

据我所知,这一直是人们想要的行为,我很困惑为什么这以前对你有效

链接器不会在每次loadLibrary调用时浏览完整的APK文件,而是在安装APK时提取正确的本机库。只使用一个架构目录,因此如果它找到lib/armeabi-v7a,它甚至不会查找lib/armeabi

在一些旧版本的android(4.0.3及更早版本)上存在一个已知的问题,即可能会意外地使用armeabi而不是armeabi-v7a,但不确定这是否正是让它看起来适合您的原因

例如,参见官方解释(第三节“Android平台上的ABI管理”,特别是第三节第3.3小节和第三节第1小节末尾的注释)

编辑:实际上,在kitkat之前的android版本上,包管理器似乎可以从辅助ABI目录安装一些文件,即使主ABI目录存在。是我的测试示例的源代码,是它的二进制代码。本例创建了四个本机库,
libgello-jni.so
libhello-jni.so
libhello-jni2.so
libtello-jni.so
。这些文件是为所有ABI构建的,但在
armeabi-v7a
中,我删除了除
libhello jni之外的所有文件。因此
-文件列表(用于ARM体系结构目录)如下所示:

/jniLibs/
    |
    +---armeabi/
    |     |
    |     +---libFirstLibrary.so
    |     +---libSecondLibrary.so
    |
    +---armeabi-v7a/
          |
          +---libFirstLibrary.so
lib/armeabi/libgello-jni.so
lib/armeabi/libhello-jni.so
lib/armeabi/libhello-jni2.so
lib/armeabi/libtello-jni.so
lib/armeabi-v7a/libhello-jni.so

在kitkat
armeabi-v7a
设备上安装时,将从
armeabi-v7a
目录安装
libhello jni.so
,从
armeabi
目录安装
libtello jni.so
,但根本不安装
libtello jni.so
。安装什么文件似乎取决于APK中的名称和顺序。因此,根据您的文件名,您以前可能有过运气,而且这是有效的——即使文档明确指出它不应该有效。在android-L预览版中,这种不一致性似乎已得到纠正。

通常是的,但几乎所有设备都支持两个ABI。在我的例子中,Nexus5支持:
CPU_ABI=armeabi-v7a
CPU_ABI2=armeabi
。同样的机制也适用于英特尔设备,其中主ABI是
x86
,而次ABI是
armeabi
,因此我的应用程序在英特尔设备上也可以正常运行,即使
x86
文件夹中没有本机库。在我看来,没有理由不在L-Preview.Yes上运行,但是如果在主ABI目录中找不到库,包管理器只检查辅助ABI目录中的库。我链接的文档说:“包管理器服务将扫描.apk并查找任何形式的共享库:lib//lib.so[…]如果找到了一个,则将其复制到
$APPDIR/lib/lib.so下。如果没有找到,并且定义了辅助ABI,则服务将扫描形式为:lib//lib.so的共享库。”。因此,如果主ABI目录不为空,它将不会检查次目录。这就是我在原始答案中的意思-它只从一个单一架构目录中提取-可以是主ABI或次ABI。我在Kitkat和L-Preview emulator以及Kitkat上对其进行了测试,
libFirstLibrary.so
取自
armeabi-v7a
文件夹和
libSecondLibrary.so
取自
armeabi
文件夹。如果两个库都必须位于
armeabi-v7a
文件夹中,或者两者都必须仅位于
armeabi
文件夹中,则这在L-Preview上不再起作用。文档文本对此不是100%清楚,但Kitkat和L-Preview之间的行为肯定有变化@mstorsjo请用此信息更新您的答案,我将接受,谢谢您的帮助!我很确定android的旧版本没有从多个架构子目录安装libs,但我做了一个测试,发现它可能会安装libs,但并不总是这样。所以对我来说,这似乎是旧版本中的一个bug,偶尔可以安装它们(取决于APK中的文件名和顺序),这个bug已经在android-L中解决了。我将用这个信息更新答案。