Android NDK UnsatisfiedLinkError:“dlopen 失败:空/缺少 DT_HASH”

问题描述 投票:0回答:10

我正在使用崩溃报告服务跟踪 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帖子)讨论构建库的问题,这会导致每次运行应用程序时都会发生此错误。 关于为什么这种情况会偶尔发生的信息很少。 这篇文章是我能找到的最接近的。

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

谢谢!

编辑:这篇文章提到了两种有条件地获取此类错误的方法;我会调查他们。

编辑2:构建文件: 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)

应用程序.mk:

APP_STL := stlport_static
APP_CFLAGS += -std=c++11
android c++ android-ndk linker java-native-interface
10个回答
5
投票

如果您是第三方构建 .so 库供其他人使用,设置

-Wl,--hash-style=both
似乎是最好的主意。这可以让您更快地加载 Gnu 风格的哈希值并向后兼容 SysV 哈希值。

如果您仅支持 Android 8 及更高版本,则无需支持 SysV 哈希。


3
投票

您尝试加载的库很可能是用

-Wl,--hash-style=gnu
构建的。直到最近,Android 才支持这一点(据我所知,甚至在 L 中也不支持)。您需要使用
-Wl,--hash-style=sysv
来构建您的库。

你是如何构建

cpplibrary.so
的?如果您没有执行任何操作来手动切换到 gnu 哈希样式,则可能是 NDK 中的错误。


3
投票

我在使用 Android Cmake 时遇到了这个问题,我已经设置了

-DANDROID_PLATFORM=23
根据 changelog,GNU 哈希样式从 API 23 开始可用,并且由于
ANDROID_PLATFORM
设置为 23,所以标记
--hash-style=gnu
被自动设置。

我只是通过降低

-DANDROID_PLATFORM=21
来解决这个问题,然后将标志设置为标志
--hash-style=both


3
投票

我的团队观察到类似的事故,但原因无关。我们的崩溃看起来像这样:

java.lang.UnsatisfiedLinkError: dlopen failed: 
  empty/missing DT_HASH/DT_GNU_HASH in
  "/data/app/~~ZxUFcGuDQcv9ij_KMRXCVQ==/app.cash.zipline.test-K-VxaF1awxuos15EVjM0lQ==/lib/arm64/libquickjs.so"
  (new hash type from the future?)

修复方法是按照 Android 指南支持 16KB 页面


1
投票

虽然出了这个问题,但是我在Android Studio导入第三方so文件的时候遇到了这个问题。最后我发现这是因为 Gradle 自动删除了产品的“so”文件,所以禁用这个选项就可以了。

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



0
投票

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


0
投票

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


0
投票

如果有人使用此项目模板为 Flutter 构建 Rust 库,请将

makefile
中的相应行更改为
ANDROID_ARMV7_LINKER=$(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/$(OS_NAME)-x86_64/bin/armv7a-linux-androideabi22-clang
将会有所帮助。


0
投票

如果您在 Android API 35 设备中遇到此问题,并且您使用的是 Android NDK r27 及更高版本,请尝试以下操作:

在 build.gradle 文件中,设置参数 -DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON:

android {
  ...
  defaultConfig {
    ...
    // This block is different from the one you use to link Gradle
    // to your CMake or ndk-build script.
    externalNativeBuild {
      // For ndk-build, instead use the ndkBuild block.
      cmake {
        // Passes optional arguments to CMake.
        arguments "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
      }
    }
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.