【问题标题】:Java native function called without loading library无需加载库即可调用 Java 本机函数
【发布时间】:2019-12-21 19:18:27
【问题描述】:

这是 linphone-Android(A Voip SDK)中 JNI 包装类实现的 GitHub 链接。

https://github.com/samueljero/linphone-mediastreamer2/blob/master/java/src/org/linphone/mediastream/video/capture/AndroidVideoApi5JniWrapper.java

如您所见,无需使用 System.load 或 System.loadlibrary 加载库即可声明和使用本机函数“putimage”。

我相信在 JNI 方法中,JVM 应该能够在运行时找到本机函数实现。而 System.load 和 System.loadlibrary 完成这项工作。但是不加载这样的库怎么可能呢?

【问题讨论】:

  • 该进程如何启动 JVM?
  • 我不明白你的问题。这些包装器将在本地构建到 aar 中。后面会用到android java代码。从那里,一切都被构建成一个apk。我是整个原生编程的新手。我认为 ART、DVM 和 JVM 在 JNI 上的工作方式相同。

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


【解决方案1】:

无需致电System.loadSystem.loadLibrary。您可以使用不同的方式注册本机代码。

默认情况下,您可以通过构建共享库并加载它来导出JNI 符号,但也可以执行其他操作。

假设您有通过创建 JVM 调用 Java 代码的本机代码 (C)。反过来,Java 代码调用本机代码。

Java

package recipeNo052;

public class Main {

  public static native int addOne(int a);

  public static void displayMessage() {
    System.out.println("Hello from Java");
    System.out.println(
      "I am calling method without System.load: " + Main.addOne(1));
  }
}

现在,假设在您的 C 代码中,您有类似这样的内容(请注意,本机函数具有“正常”名称 - 没有基于 JNI 的前缀等)

C

JNIEXPORT jint JNICALL addOne(JNIEnv *env, jclass obj, jint a) {
  return a + 1;
}

一旦你创建了你的JVM,你就可以做这样的事情

JNI_CreateJavaVM (&jvm, (void **) &env, &vm_args);

....
....

static JNINativeMethod methods[] = {
  {"addOne",    "(I)I", (void *)&addOne}
};

...
...

jclass cls_Main = (*env)->FindClass (env, "recipeNo052/Main");

...
...

(*env)->RegisterNatives(
  env, 
  cls_Main,
  methods, 
  sizeof(methods)/sizeof(methods[0]));

...
...

现在,每当您调用 Main.addOne 时,您实际上是从您的 main 代码调用 addOne 函数。

示例代码

> git clone https://github.com/mkowsiak/jnicookbook.git
> cd jnicookbook/recipeNo052
> make all
> make test
> make clean

你应该得到这样的东西

> make test
lib/recipeNo052_main
Hello from Java
I am calling method without System.load: 2

你可以在这里找到 repo:https://github.com/mkowsiak/jnicookbook.git

【讨论】:

  • 非常感谢您的回复。我不知道可以从本机代码启动 JVM。今天,我想通了这个问题。从类定义本身加载库不是强制性的。事实上,您可以在代码中使用该类之前使用不同的方法加载它。 JVM 稍后将通过损坏的命名约定将其链接到类。
  • 是的,例如,您可以使用LD_PRELOAD。通常,您必须确保符号对JVM 可见。
猜你喜欢
  • 2012-07-12
  • 1970-01-01
  • 2021-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-18
  • 2013-01-10
相关资源
最近更新 更多