I'm working on Android application which is a network utility. One of the utility is traceroute implementation using activity and xml file. Implementing traceroute in java is kind of a pain, so I looked to JNI and C code. There's a utility that include many linux tools called busybox. It is open source and has traceroute. here's the code on github https://raw.githubusercontent.com/mirror/busybox/master/networking/traceroute.c
My question is how can I implement JNI interface in java for this file. The file one compiled acts as a command line tool which you run and pass the parameter of the host you want to traceroute. Does that mean I have to implement only the main method in JNI. Also, this file doesn't have the JNI type methods so I wont be able to interface directly with it. Do I need to create another C file that calls traceroute main method using JNI C code. Any input appreciated
You want to call this method: common_traceroute_main(int op, char **argv)
You have to create shared library using the code from github. Take a look here
http://jnicookbook.owsiak.org/recipe-No-001/
Once you have your library, you have to prepare parameters inside Java and pass them to JNI code, where you need to unpack them and convert to what is expected by common_traceroute_main.
For example. You can pass array of String and convert them to char **argv.
http://jnicookbook.owsiak.org/recipe-No-009/
Then, all you have to do is to call common_traceroute_main from your JNI wrapper.
Solution draft
You will need Java code, for example, something like this
public class TraceCaller {
public static native callTraceRoute(int op, String[] args);
}
once you compile it using javac -h headers TraceCaller you will find C header file.
Inside this header file, you will have to extract values from array of strings. Take a look here (https://github.com/mkowsiak/jnicookbook/blob/master/recipes/recipeNo038/java/recipeNo038/PassHashMap.java) to get the feeling of how to retrieve String objects from array inside JNI code and turn them into char*.
Once you have (inside JNI) both: int op and array of char * you can simply call routine: common_traceroute_main.
Once it's finished, you have to pass data back (either as return value or via object passed to JNI).
Take a look here on sample that shows how to pass String back to Java:
https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo010
And, you are done :)
Related
I have a native function :
int NativeFunction(std::vector<MyObject>);
I am loading the Native dll using JNA and I am trying to call this function NativeFunction from Java like:
nativedlljnapointer.NativeFunction(List<MyObject>);
I am however running into "java.lang.IllegalArgumentException: Unsupported argument type ArrayList" exception.
I al tried using java util vector when I am running into the same exception "java.lang.IllegalArgumentException: Unsupported argument type java.util.Vector"
Can someone suggest me how I could pass List from my Java function to the native function which has vector<> as an argument.
Any help will be greatly appreciated.
std::vector and java List are completely different types, it's normal for them not to work.
Furthermore , Is MyObject a C++ defined object or a Java defined object (if you define one in each, they are again, completely different objects ! )?
The best and safest way to communicate via JNI is to use serialization, like you would between any two different environments.
Granted, it takes a bit of extra work, but in the long run you end up with more robust code.
I am trying to inspect a Java class and automatically retrieve all of its methods and fields in a way that I can invoke them via JNI on Android. However, I can't figure out how to actually get the textual signature string programmatically; I know how to get it via javap -s from the command line but I would like to get it from within my program.
The closest I can find is using clazz.getMethods() to get the individual methods, and then Method.toGenericString() to get a human-readable string, but that string is formatted like the Java code signature (e.g. public int someMethod(int foo, java.lang.String bar)) when I really just want the JNI-style signature (e.g. (ILjava/lang/String;)I), as I will need that string to call getMethodID() from JNI and I already have a perfectly-good parser that parses those JNI signatures in the first place.
I could just manually maintain bindings for the classes I actually care about accessing from JNI, but I'd much rather just have everything handled as automatically as possible; less code is better, after all.
I did find ASM which provides helper methods for this, but it appears to be a bytecode generation framework and I am not sure if it will be compatible with Android.
Or, in other words, given the following class:
class SomeClass {
String foo(int bar) { return "This is foo " + bar; }
}
I want to create a class called ClassInspector which can do something like:
ClassInspector ci = new ClassInspector(SomeClass.class);
int n = ci.getMethodCount(); // returns 1
String name = ci.getMethodName(0); // returns "foo"
String sig = ci.getMethodSignature(0); // returns "(I)Ljava/lang/string;"
Which is to say that I want to be able to get the output of javap -s from within Java, so that I can call Java methods from the native side.
I had the same problem and I don't find a "clean" solution.
Finally, I decided to create a dummy class with same methods but declared as native.
Then I use javah to create the header file and I take the signature from that header file.
I know that it does not look nice... but I don't find a better option (except creating it "manually" based on the Method properties).
I have created swig interface file to create JNI for my C++ Files. but some of my C++ Files include functions which accept pointer as argument like (void*) , C++ BOOL and Swig converts it into
type like SWIGTYPE_p_int32_t how to pass such kind of data type from java ?
for example one of the function's actual prototype is like below in C++
DLL_API void DLL_CALLCONV FreeImage_Initialise(BOOL load_local_plugins_only FI_DEFAULT(FALSE));
which is converted in Java file with swig
public static void FreeImage_Initialise(SWIGTYPE_p_int32_t load_local_plugins_only)
how to pass such value from java ?
I have many classes which include such kind of arguments in function.
is there any way so that I can apply solution to bulk files for handle datatype as simple as possible.
I have read one way to do that is create helper function but I cannot go for it because i have many c++ classes and for each and every function creating helper function for returning pointer is not way to go.
Please suggest any other way if possible.
Solved myself. Swig was not be able to recognize all the typedef in header files and hence it was producing that kind of Types in wrapper. I need to redefine them in Interface file.
About booleans, I would recommend using boolinstead of BOOL because JNI directly provides a type signature for it: Z (you can check signatures at: JNI Types and Data Structures)
About pointers, if are pointer to basic types, this is declared by adding [in front of corresponding signature, this is: int* --> [I. If it's a pointer to a own class, swig will create a fully qualified class.
Hope this helps.
This is because of the weird declaration of BOOL type.
In this particular case, you can pass an int there from Java side. Either 0 or 1 will do the right job.
Or you can change BOOL to bool in your native code by creating a small wrapper for this library.
SWIG doesn't know about windows types. Add %include <windows.i> to the interface definition.
How can I pass Parameters to Main via JNI?
Currently I load my DLL like:
class SharedLibrary {
native void GetBuffer(ByteBuffer Buffer);;
SharedLibrary(String[] exec_args) {
String path = new File(exec_args[0]).getAbsolutePath();
System.load(path); //Load My DLL. I want to Pass this DLL some arguments.
ByteBuffer Foo = ByteBuffer.allocateDirect(.....);
GetBuffer(Foo);
}
}
How can I pass the DLL arguments? I need to pass multiple arguments.
The purpose of loading a library into Java is to fulfill Java methods which are declared with the native attribute, such as native void methodname(_arguments go here_);. You can declare one or more native methods in a class, but all of them are expected to be defined (using JNI standards) in your DLL. From Java, you call them like any other method (by using whatever arguments are defined for the method).
If there are data elements you want the DLL's initialization entry point to receive, you need to make them static members (or methods) of some class and the DLL needs to know to access that class to get them. This, however, would be quite abnormal and is probably not the best way to perform whatever it is you're looking to do.
Well, if you need "multiple parameters", any existing "dll main" won't work for you. You are most probably referring to WinAPI DllMain and you probably think that this function is mandatory to any DLL, much the same way as every C executable is expected to have main() function. It is not. JNI in particular has JNI_OnLoad which doesn't take any parameters, but so DllMain doesn't have any user-definable "multiple parameters" per your requirement. If you need your own parameters, why can't you create an initialization method? Even the DllMain doc is recommending that. DllMain is very limited in what it can do. Make the JNI init method static, so that you can call it before instantiating the SharedLibrary object in Java. What's the problem with it? Tell something about the "multiple parameters" you need so much.
I'm attempting to call native methods within a 3rd party DLL, which has a C interface with methods such as:
DWORD ExampleInterfaceMethod( DWORD Mode, LPSTR Header );
I've successfully loaded the DLL using:
System.loadLibrary("DLLName");
and I've created a method:
protected native int ExampleInterfaceMethod(int type, int Nth, byte[] name);
This method doesn't seem to be using the correct variable types, as whenever I call it the following error is thrown: java.lang.UnsatisfiedLinkError: com.DLLTest.ExampleInterfaceMethod(II[B)I
What variable types do I need to use in Java in order to call this method, or am I missing something else?
With JNI, you need specially-named C functions to implement your Java native methods. You can't simply add a native method to call an existing C function - instead the normal way is creating a "wrapper" C function which calls the existing one, and is named the right way.
You might want to have a look at JNA. This is a wrapper around JNI which allows you to call C functions from the Java side without manually writing adapting native code for this.