Android NDK UnsatisfiedLinkError: "dlopen failed: empty/missing DT_HASH"

Android NDK UnsatisfiedLinkError: "dlopen failed: empty/missing DT_HASH"

我正在使用崩溃报告服务跟踪我们的 Android 应用程序(使用 NDK 加载自定义 C++ 库)的崩溃。少数用户遇到以下崩溃:

java.lang.UnsatisfiedLinkError: dlopen failed: empty/missing DT_HASH in "cpplibrary.so" (built with --hash-style=gnu?)
   at java.lang.Runtime.loadLibrary(Runtime.java:365)
   at java.lang.System.loadLibrary(System.java:526)

我可以在互联网上找到关于此错误的几次提及(例如,这个 Google Groups post) discuss problems with building the libs, which cause this error to occur every time the app is run. There is little information on why this might happen sporadically. This post 是我能找到的最接近的。

根据崩溃痕迹,似乎任何特定用户都会不断地经历这种情况;我不确定这些用户是否能够正确加载库。有没有人知道什么可能导致这种情况有时发生?我可以做不同的 NDK 构建来尝试阻止它吗?

谢谢!

编辑:This post 提到了两种有条件地获取此类错误的方法;我会关注他们。

Edit2:构建文件: Android.mk(摘录):

include $(CLEAR_VARS)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
LOCAL_C_INCLUDES := <Source Path>...
LOCAL_CFLAGS := -DANDROID -Wall
LOCAL_CPPFLAGS := -DENABLE_SDK_DEBUGGING=1 -DENABLE_SDK_LOGGING=1
LOCAL_MODULE := cpplibrary
LOCAL_SRC_FILES := <Source Files> / ...

LOCAL_LDLIBS    := -llog -landroid
LOCAL_STATIC_LIBRARIES := cpplibrary
include $(BUILD_SHARED_LIBRARY)

Application.mk:

APP_STL := stlport_static
APP_CFLAGS += -std=c++11

这可能是由于目标设备的架构不同所致。您是否能够从崩溃报告中收集设备 vendor/model 信息? 不确定,但我想您需要跨多个架构(armeabi、armeabi-v7、neon)编译本机库以克服此类不兼容性。

您尝试加载的库很可能是使用 -Wl,--hash-style=gnu 构建的。 Android 直到最近才支持此功能(据我所知,这甚至不在 L 中)。您需要使用 -Wl,--hash-style=sysv.

构建您的库

您是如何构建 cpplibrary.so 的?如果您没有手动切换到 gnu 哈希样式,则可能是 NDK 中的错误。

要查看它是否是散列式问题,您可以 运行 readelf -d cpplibrary.so 并查找 GNU_HASH 部分。如果有 - --hash-style=sysv 应该可以解决问题。

如果您是第三方构建 .so 库供他人使用,设置 -Wl,--hash-style=both 似乎是最好的主意。这使您可以更快地加载 Gnu 风格的散列和 SysV 散列的向后兼容性。

虽然出了这个问题,但是我在Android Studio import third-party so文件中遇到了这个问题。最后我发现这是因为 Gradle 自动删除了产品 'so' 文件,所以禁用此选项它有效。

android {
 ........
    packagingOptions{
        doNotStrip "*/armeabi-v7a/*.so"
    }
   .......
}

--hash-style=both 应该可以。检查 https://android.googlesource.com/platform/bionic/+/master/android-changes-for-ndk-developers.md#gnu-hashes-availible-in-api-level-23 作为参考。

我在使用 Android Cmake 时遇到过这个问题,我设置了 -DANDROID_PLATFORM=23 根据 changelog GNU 哈希样式从 API 23 开始可用,并且由于 ANDROID_PLATFORM 被设置为 23,标志 --hash-style=gnu 被自动设置。

我已经通过降低 -DANDROID_PLATFORM=21 来解决这个问题,然后将标志设置为标志 --hash-style=both

如果有人使用 this project template 为 Flutter 构建 Rust 库,将 makefile 中的相应行更改为 ANDROID_ARMV7_LINKER=$(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/$(OS_NAME)-x86_64/bin/armv7a-linux-androideabi22-clang 将会有所帮助。