My android project requires some C++/C libraries,and I've got a library (.so) and some headers(.h). and I have reference to some simple demo, using JNI bridge some simple functions, but This lib is complicated for me. How bridging these complex objects and callback.
Created a android project
Copy xxx.so into lib/armeabi, copy all .h files to jni folder.
I want use JNI bridging these c ++ function, I konw I need creat a MStack.h and MStack.cpp to implement these functions, But these headers class makes me very confused,I'm not familiar with C++
some .h like this :
class SIPSTACK_API ISipStack : public Component::IUnknown
{
public:
class IFactory : public Component::IFactoryUnknown
{
public:
virtual ISipStack* create() = 0;
static const char* iid() {return "SipStack";}
};
public:
virtual ~ISipStack(void){}
///#brief
///\param [in] config
///\note
virtual bool setConfig(SipConfigInfo& config)
COMPONENT_UNIMPLEMENTED_OPERATION
///\param [in] handler
///\note
virtual bool start(void)
COMPONENT_UNIMPLEMENTED_OPERATION
///#brief
enum
{
inviteHandler = 0,
actRegHandler,
pasRegHandler,
outCallMsgHandler,
subscribeHandler,
proxyHandler
};
/// #brief
///\param[in] type inviteHandler、registerHandler
///\param[in] handler
///\note
virtual bool attachHandler(int type, Component::IUnknown* handler)
COMPONENT_UNIMPLEMENTED_OPERATION
.....
How can I put these into the corresponding .h and implemented in the cpp. Thanks!
Related
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.
I am trying to bind a native function to Java using JNI RegisterNatives. If the function is in the global scope I can easily bind the function and it works without an issue.
But when I am trying to bind a C++ class member function to Java the callback doesn't get called.
The declaration of my C++ function is like this:
void native_onCall(JNIEnv* env, jobject obj, jint val)
The Java function looks like this.
public native void onCall(int a);
The native function I am trying to bind is in the same class as my RegisterNatives method call. Here is a snippet of how I used a typedef to define the function pointer and added it to JNINativeMethod struct.
typedef void (MyClass::*func_pointer)(JNIEnv*, jobject, jint);
func_pointer cbptr;
JNINativeMethod[index].name = const_cast<char*>("onCall");
JNINativeMethod[index].signature = const_cast<char*>("(I)V");
JNINativeMethod[index].fnPtr = (void*)cbptr;
env->RegisterNatives(jclass, JNINativeMethod, index);
I also used std::bind and a lambda function to bind the function pointer but it doesn't work.
If anyone can point out a way to bind a class member function to java using JNI or what I am doing wrong here it would be really helpful.
Apparently using an instance member function is not the way to go at this.
By using a static function I managed to handle the call inside a class.
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.
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);
}
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);
}