Android NDK - Include a c++ header in a different header? - java

I have an Ability.h file that is dependent on an Effect.h file.
I need to use javah to generate my header, but I'm unable to define an Effect dependency in my Ability.java class from which I'd like the c++ header to be generated.
Example:
public class Ability {
static {
System.loadLibrary("com_test_Effect");
System.loadLibrary("com_test_Ability");
}
public native Effect foo(Effect x);
}
This code generates an *.h file without the foo() function, as if it couldn't recognize it. It does generate a proper file if I swap the return type to int and don't include the com_test_Effect.
I do have both of the modules defined in the Android.mk file (com_test_Effect and com_test_Ability).
How to include an another c++ file directly in the Xyz.java class from which the *.h is generated by javah ?
Edit: The question can also be asked like this: Is there a way to pass C++-type arguments or return a C++-type value from a function that is an interface between C++ and Java ? (The interfacing medium being JNI.) For example, you can do so with basic types like int which then gets converted to jint and so on.

What about returning an Object:
private native Object fooNative(Object x);
Then convert it so that it has the same signature:
public Effect foo(Effect x) {
return (Effect)fooNative(x);
}

Related

JNI / JNA Unsatisfied Link, but symbol is present

i am trying to integrate a legacy system via a provided c-library "libext.so".
To test JNA/JNI i want to call the "setProperty" function.
objdump libext.so -t | grep setProperty
0000000000104d50 g F .text 000000000000000e Java_ExtClass_setProperty
0000000000104be0 g F .text 000000000000016a Java_com_company_ExtClass_setProperty
this is my code, using java 8, jna 4.5.1 and/or native jni, both ways fail with an UnsatisfiedLinkError when calling the function - loading the library works without an Exception.
public class TestClass
{
static {
try {
System.load("/path/to/libext.so");
} catch (Throwable e) {
e.printStackTrace();
}
}
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)
Native.loadLibrary(("/path/to/libext.so"), CLibrary.class);
void setProperty(String key, String value);
}
public static native synchronized void setProperty(String key, String value);
public static void main(String[] args) {
// setProperty("a", "b");
CLibrary.INSTANCE.setProperty("a", "b");
}
}
what am i missing?
#Update:
I now moved both, the JNI class and the JNA INterface to the correct package and renamed the jna interface
package com.company;
public interface LibExtLibrary extends Library {
LibExtLibrary INSTANCE = (LibExtLibrary)
Native.loadLibrary(("/path/to/libext.so"),
LibExtLibrary.class);
void Java_com_company_ExtClass_setProperty(String key, String value);
void Java_ExtClass_setProperty(String key, String value);
void ExtClass_setProperty(String key, String value);
void setProperty(String key, String value);
}
calling the first two methods on INSTANCE gives an InvalidMemoryAccess, the second two an UnsatisfiedLinkError.
The JNI Method worked, as soon as the fully qualified classname was equal to the one defined in the native library
If the question is "why can't I call JNI methods with JNA?":
To be able to call external libraries from Java you have to use JNI. You declare some methods as native and javah will generate special functions for you that you can fill in with your code. Every function will have two additional arguments: an env pointer that is bound to the calling Java thread and the object or class that is the method receiver. If you pass a Java object as one of the other arguments you will get a jobject in your function.
If the implementation of the JNI functions would only consist of forwarding the calls to another external library you can also use JNA. JNA uses JNI to wrap libffi so you can call an existing external library directly. This way you don't have to create a wrapper library yourself. JNA will not create an env pointer or pass the method receiver as argument. And it will try to marshal all the other arguments into something the external library understands. That means no jobjects here.
Summary: JNI calls functions explicitly created for it and the arguments are Java specific. JNA uses JNI internally to call functions in non-Java external libraries.

Kotlin integration in Java Code?

Example:
In C-code it is possible to call parts of assembler code, like:
int main()
{
//... stuff
__asm
{
lea ebx, hal
mov ecx, [ebx]hal.same_name ;
mov esi, [ebx].weasel ;
}
// .. further stuff
return 0;
}
Is such a code integration possible for Kotlin code in Java (*.java) files?
(I am not talkin about JNI or C/C++ in Java!)
I would like to extend already existing (AndroidStudio-) Java-Source-Code with Kotlin language.
//.. this is *.java file
public class MyAlreadyExistingJavaClass {
private int memberVar;
public MyAlreadyExistingJavaClass()
{
}
// this is Kotlin within *.java file
// extend this Java file with this constuctor in KOTLIN ?
// would make above default constructor unneccessary.
class MyAlreadyExistingJavaClass(number: Int = 0)
{
memberVar = number;
}
}
Java does not provide any syntax for including snippets of code in Kotlin or any other language into a Java file. However, this is not necessary to accomplish your task. You can simply define the constructor you need as a factory function in a separate Kotlin file:
fun MyAlreadyExistingJavaClass() = MyAlreadyExistingJavaClass(0)
If you want to define a new method, rather than a constructor, you can use extension functions.
I am a Groovy developer, not a Kotlin developer, but it looks like Kotlin provides a scripting API. Groovy, JavaScript and JRuby can all be called from within a Java class using the standard Java ScriptEngine API. You would want something like that to approximate inlining Kotlin within a Java class. I say approximate because it wouldn't be run directly like that assembly example, but would be passed through a ScriptEngine-compliant Kotlin implementation.

JNI wrapped DLL only works when called from the default package

I have been given a DLL and a JNI wrapper which are used to access a business card scanner.
So far I have only been able to call the API when all classes are in the default package. When I try to move classes to other packages I get an UnsatisfiedLinkError.
I have had no experience of JNI up until now and wonder if I need to rewrite the wrapper of if I can organise the project in a different way. What I cannot do is to use the default package as this would mean putting all my classes there.
The wrapper looks something like this:
public final class Wrapper {
private native int CRTK_Init(int[] lphRTK);
private int m_hRTK;
private int m_hRTKDB;
static
{
System.loadLibrary("crtk_jni");
}
public Wrapper() {
m_hRTKDB = 0;
int[] pRTK = new int[1];
CRTK_Init(pRTK); // UnsatisfiedLinkError here
m_hRTK = pRTK[0];
}
}
The thing with JNI is that the fully qualified class name of the class containing the native methods is tightly coupled to the method-signature of the native (C-)functions.
The C-signature must be something like
JNIEXPORT jobject JNICALL Java_packageName_className_methodName(JNIEnv * env, jclass parameter)
Renaming the class or moving it to another package would change the expected function-name and result in an UnsatisfiedLinkError.
So what can you do?
Unless you have access to the native sources to change the function-names all classes that come as a bundle together with the dll must remain in the default-package, all your own classes can go where you want to have them.
Getting a JNI-package that has its native methods in the default-package is considered poor style and does not bode well for the quality of the received software. And be prepared for further trouble than can come from using the default package, AFAIR e.g. tomcat had (has?) problems with those.

Loading a static void C function via AndroidfromJNI another Package

I am trying some things out with JNI and by that I found the following problem:
If I want to use a native function in Java I load the needed lib, in which the needed function is stored, via
static{
System.loadLibrary("lib");
}
and use
native private static int calculate(byte[] numberArray);
to declare the native method in the java file. During the program itself I can use this function to calculate something with:
int result = calculate(array);
This works only if I compiled the shared object with the header-file created by javah so that each function is named on c side as:
static void Java_com_packagename_File_calculate(const void* array, void* result){
code[...]
}
If I delete the reference in the java code ("native [...] calculate[...]")to this c function; is there any possibility to access / execute the still existing c-code via java (of course without editing the exisiting file ;-)) for example via reflections or inheritance? Or is there something possible like:
public class NewClass{
public int nativeCheater(){
System.loadLibrary("lib");
native private static int Java_com_packagename_File_calculate;
}
}
It is important that I want to use a whole new class without any relations to the prior used package com.packagename.(File).
Thanks in advance :-)
No, but you can create a new class with same package and class name and access the same native method. The new class can declare this method public.
An alternative is to use dynamic binding via Jni_OnLoad() and RegisterNatives(). This way, your native implementations may bind to any Java class, or even more than one.
But if you have access neither to the Java class nor to the native source, you can always create your own native method, in your own class, and inside your C explicitly call the original:
static void Java_com_mypackagename_File_calculate(const void* array, void* result) {
Java_com_packagename_File_calculate(array, result);
}

JNA direct call not working with argument Structure[]

I have a C++ function:
struct Result {
//...
};
bool doSomething(Result[]);
If I use the following JNA binding, the function call works fine:
public class Result extends Structure {
//...
}
public interface CPPLibrary extends Library {
public static final CPPLibrary INSTANCE = (CPPLibrary)Native.loadLibrary("dllname");
boolean doSomething(Result[]);
}
But with direct call, I hit an IllegalArgumentException saying class [Lcom.usta.Result; is not a supported argument type (in method calcPV01 in class com.usta.CPPLibrary). My JNA code for the direct call-mapping:
public class CPPLibrary implements Library {
Native.register("dllname");
public static native boolean doSomething(Result[]);
}
I can see in com.sun.jna.Function#convertArgument() explicitly handles Structure[] but com.sun.jna.Native#getConversion(), which is used by direct call-mapping, does not handle Structure[].
The conversion is trivial, just call Structure.getPointer() on the first element of your structure array (assuming that you got the array from Structure.toArray in the first place).
You're actually better off with that when using direct mapping; when passing non-primitive, non-pointer types the JNI layer has to call back into the VM to derive the appropriate native data.
Feel free to file an issue for support of Structure[] arguments in direct mappings. That should be supported (JNA documentation notes that arrays of Pointer/String/WString/NativeMapped are not supported).
If I use a different method signature:
boolean doSomething(Pointer results);
it does work. But then I have to convert from Result[] to a Pointer my self.

Categories

Resources