【问题标题】:Android NDK cmake JNI static libraryAndroid NDK cmake JNI 静态库
【发布时间】:2016-10-10 19:07:31
【问题描述】:

出于安全考虑,我想静态链接所有库,包括包含 JNI_OnLoad 函数的本机库。我已经读过可以静态链接 JNI 库(http://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#library_version),但我无法使用 Android Studio 进行链接。有可能吗?

这是我目前拥有的。

在 Java 代码中:

System.loadLibrary("testlibrary");

在 cmake 生成文件中:

add_library( testlibrary
         STATIC
         ${mysources} )
target_link_libraries(testlibrary)

在 C++ 文件中:

extern "C" {
EXPORT
JNIEXPORT jint JNICALL JNI_OnLoad_testlibrary(JavaVM *vm, void *reserved) {
   ...
   return JNI_VERSION_1_8;
}

使用 Android Studio 构建应用程序失败,因为它试图查找 *.so 库文件:

java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip 文件 "/data/app/xxx-1/base.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]] 找不到“libtestlibrary.so”

【问题讨论】:

  • target_link_libraries 至少接受 2 个参数:可执行文件/库和其他与之链接的库。在您的代码中,您只传递一个参数。
  • 您试图通过使用静态库而不是动态库来解决哪些安全问题?静态库(如果有的话)包含比共享库更多的信息,而不是更少。
  • 我试图避免有人决定用自定义库中的假函数覆盖共享库中的函数。
  • Tsyvarev,我认为附加参数是可选的。实际上,我在第一个参数之后列出了其他库,但这与我的问题无关)

标签: android android-ndk cmake java-native-interface


【解决方案1】:
System.loadLibrary("testlibrary");

这一行试图加载libtestlibrary.so,显然它没有被构建并打包到APK中,因为这个名字的库是静态库:

add_library( testlibrary
         STATIC
         ${mysources} )

您在这里描述了目标libtestlibrary.a,它是不可加载的,并且只能与可加载的.so 链接。因此,为了达到预期的效果,您应该将testlibrary 声明为共享的,然后将其链接到另一个静态库。结果,您将获得一个可以加载到程序地址空间的单一共享库。例如

add_library(testlibrary SHARED ${mysources})
add_library(lib1 STATIC ${lib1_src})
add_library(lib2 STATIC ${lib2_src})
...
target_link_libraries(testlibrary lib1 lib2 ...)

【讨论】:

  • 这就是我目前拥有的——链接多个静态库的共享库。但这不是我想要的。我认为有一种方法可以将所有本机代码放在静态库中,避免共享。正如我提供的链接中所建议的那样:If a library L is statically linked, then upon the first invocation of System.loadLibrary("L") or equivalent API, a JNI_OnLoad_L function will be invoked with the same arguments and expected return value as specified for the JNI_OnLoad function.
  • @jozols 似乎这句话是关于 Android 目前不支持的功能。只有共享库在 APK 中才有意义,并且可以被 Android 运行时识别。
  • 需要共享lib才能加载,如windows上的dll。
  • Java 8 确实向 JNI 添加了静态链接。但是,当从与该静态库链接的 C 可执行文件加载 Java VM 时,此方法有效。在 Android 中,这意味着您需要一个与您的静态库链接的自定义 zygote。
猜你喜欢
  • 2017-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
  • 2016-04-15
相关资源
最近更新 更多