【问题标题】:when to use JNIEXPORT and JNICALL in Android NDK?何时在 Android NDK 中使用 JNIEXPORT 和 JNICALL?
【发布时间】:2013-10-25 16:52:54
【问题描述】:

我正在尝试编写自己的 jni 资源。查看一些 ndk 示例,我发现他们经常使用这些宏 JNIEXPORT 和 JNICALL 后跟 java 包的名称这样的

JNIEXPORT void JNICALL Java_com_example_plasma_PlasmaView_renderPlasma(JNIEnv * env, jobject obj, jobject bitmap, jlong time_ms)

我用谷歌搜索过,但我不明白何时以及如何使用这些宏

【问题讨论】:

    标签: android c++ macros android-ndk java-native-interface


    【解决方案1】:

    简单来说:

    • JNIEXPORT 如果你应该使用 registerNatives 系列函数,那么你不应该使用 JNIEXPORT。否则,您必须使用它。
    • JNICALL 必须始终使用。

    JNIEXPORT 确保函数在符号表中可见。 JNICALL 确保函数使用正确的调用约定。在 Android 上,JNICALL 具有基于架构的不同值。 ARM 是空的,这可能会欺骗您不包含它。但是你必须使用 JNICALL。

    registerNatives 允许您在JNI_onLoad 或将来某个时候以编程方式链接该功能。 registerNatives 允许更早地捕获错误的函数名称,我推荐这条路线。

    【讨论】:

      【解决方案2】:

      JNIEXPORT 和 JNICALL 在 NDK_ROOT/platforms/android-9/arch-arm/usr/include/jni.h 中定义。根据您的设置,此路径会有所不同,但大多相似。

      #define JNIIMPORT
      #define JNIEXPORT  __attribute__ ((visibility ("default")))
      #define JNICALL
      

      JNIEXPORT 用于使本地函数出现在构建的二进制文件(*.so 文件)的动态表中。它们可以设置为“隐藏”或“默认”(更多信息here)。如果这些函数不在动态表中,JNI 将无法找到调用它们的函数,因此 RegisterNatives 调用将在运行时失败。

      值得注意的是,所有函数默认都在动态表中,因此任何人都可以很容易地反编译您的本机代码。每个函数调用都内置在二进制文件中,以防 JNI 需要找到它。这可以使用编译器选项-fvisibility 进行更改。我建议大家将其设置为 -fvisibility=hidden 以确保您的代码安全,然后使用 JNIEXPORT 将函数标记为具有外部可见性。

      使用 strip 命令只是删除调试符号,动态表是独立的。玩 objdump 看看一个人可以从你的 .so 文件中得到多少。

      我们最近被这个绊倒了,希望这对某人有所帮助。

      编辑:我们使用自定义构建系统,因此默认情况下可以为其他构建设置设置可见性选项。更多信息请访问this SO answer

      【讨论】:

      【解决方案3】:

      您可以在 JNI 包含的机器相关部分中找到这些宏的定义(通常在 $JAVA_HOME/include/<arch>/jni-md.h 中)。

      简而言之,JNIEXPORT 包含确保正确导出给定函数所需的任何编译器指令。在 android(和其他基于 linux 的系统)上,这将是空的。

      JNICALL 包含确保使用正确调用约定处理给定函数所需的任何编译器指令。在 android 上可能也是空的(它是 w32 上的 __stdcall)。

      一般来说,你应该把它们留在里面,即使它们是空的#defines。

      【讨论】:

      • JNICALL 在 Android 的某些架构上不是空的。应始终使用 JNICALL。如果您不使用 registerNatives 系列函数,则应使用 JNIEXPORT。
      【解决方案4】:

      只需在您的本机类上运行“javah”并使用它生成的任何内容。当您拥有可以 100% 可靠地生产它的工具时,您无需了解其中的来龙去脉。

      【讨论】:

      • 我不知道这个命令。我在 ndk-build 之前使用它?
      • 我对ndk-build一无所知,但是我已经做了15年的JNI,如果没有javah和javap我将无处可去。您可以随时查看。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-18
      • 1970-01-01
      • 2011-03-29
      • 1970-01-01
      • 1970-01-01
      • 2011-01-14
      • 2014-06-09
      相关资源
      最近更新 更多