在Java中动态调用本机方法

时间:2014-06-26 11:13:29

标签: java c java-native-interface

我正在制作软件(适用于Android)以读取传感器的仪表值。 该软件预计会经常接收更新,以支持更多传感器。读取这些传感器的仪表数据的功能是在应用程序在运行时下载的本机库中实现的。

我有一个共享对象列表和一个应该调用的入口函数(保存返回值):

libprintf.so,hookPrintf
libharx.so,hookHarx

每个库都在运行时加载:System.loadLibrary("printf");

每个函数的签名如下所示:

public native int hookPrintf();
public native int hookHarx();

问题是我事先不知道(在编译时)必须加载哪些共享对象,因此我无法在java源代码中添加这些签名。

我尝试使用Reflection来动态调用方法,如下所示:

Method entryMethod = Expat.class.getMethod(hookMethod);
Object test = entryMethod.invoke(this);
System.out.writeln(test.toString());

但是,如果签名不存在,则仍会因NoSuchMethodException而失败。有没有其他方法可以调用本机方法而无需事先定义它们?

编辑: 使用RegisterNatives函数,我可以从共享对象动态注册我的函数,但仍然需要在类中定义方法签名。 What does the registerNatives() method do?

2 个答案:

答案 0 :(得分:3)

您可能只有两个本机方法的Java类,并依赖于RegisterNatives和UnregisterNatives并在运行时切换加载的本机实现。有了这个,我宁愿使用本机包装库和本机方法

private static native void hook(String libName, String hookName);

这个包装器将使用dlopen()或LoadLibraryEx(),并在必要时卸载外部库。

在某些JVM中,您可以动态创建新类,但这非常棘手。

答案 1 :(得分:1)

您有一个基本的设计问题。我建议返回并创建一个JNI库,它实现一个方法,如public native int createHook()或类似的东西。然后根据某些条件在您的本机代码中进行选择。如果您仍然希望/需要在运行时加载库,请为libprintf.so和libharx.so创建非jni库,并使用dlopen动态加载库或将库弱链接到jni库。