Android NDK calling native method with different namespace - java

i'm new from JNI programming
Can i call a native method like from a different JNI namespace definition?
For example:
package com.example.hellojni;
public class HelloJni extends Activity
{
public native int MyMethod();
public native int OtherMethod(); // this works have the namespace package=jniexport interface
static {System.loadLibrary("hello-jni");}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
int b = OtherMethod(); //works
int a = MyMethod(); //ERROR java.lang.reflect.InvocationTargetException
}
}
================File.c================
JNIEXPORT int JNICALL Java_Cardioline_HelloJni_MyMethod(JNIEnv *env, jobject thisObj)
{
return 1;
}
JNIEXPORT int JNICALL Java_com_example_hellojni_HelloJni_OtherMethod(JNIEnv *env, jobject thisObj)
{
return 2;
}

No, the JNI method name is predetermined by javah. Try starting here:
http://blog.edwards-research.com/2012/04/tutorial-android-jni/
javah will provide you with the header and you must copy the method declarations into your .c file.
If you have a JNI method in another class that you want to call, call the other class in java. Basically change this:
int a = MyMethod();
to this:
int a = new CardioLine.HelloJni().MyMethod();
Typically, I have a one-to-one mapping of Java files to .c/.cpp files. That's probably what you want too (for Java classes with native methods).

As #JonnyBoy explained in his answer, the name of a JNI native function is tightly coupled with the full name of the Java class that uses this function as a native method. The full name of HelloJni class in com.example.hellojni package is com.example.hellojni.HelloJni, thus it looks for native functions which names start with Java_com_example_hellojni_HelloJni_.
Luckily, there is no requirement in Android for all your classes to be under the app package. For example, your app that is registered as com.example.hellojni is free to include and use a package CardioLine and class CardioLine.HelloJni.
The directory structure for a simple Android project will include a tree like this:
src
com
example
hellojni
HelloJni.java
CardioLine
HelloJni.java
On the other hand, if you include JNI_OnLoad() function in your native library, and use RegisterNatives(), your Java class can have native methods regardless of their exported names.

Related

Adding native hooks dynamically

Is there some way to add native hooks dynamically using JNI? What I mean by that is, I would like to override some methods in a class (or in a new class) so that the override calls my native code, without writing any Java code for that.
If you are referring to native methods, maybe registering might be the answer for you.
For example, here, I am registering native method
JNIEXPORT jint JNICALL addOne(JNIEnv *env, jclass obj, jint a) {
return a + 1;
}
...
...
static JNINativeMethod methods[] = {
{"addOne", "(I)I", (void *)&addOne}
};
...
...
(*env)->RegisterNatives(env, cls_Main,
methods, sizeof(methods)/sizeof(methods[0]));
that will be assigned to class
public class Main {
public static native int addOne(int a);
...
...
}
Full sample: https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo052

Java extends C++ class [duplicate]

I have a C++ library that I have to use in an existing Android implementation. I'm using Android NDK and using the C++ classes via JNI.
However, I am not able to find how to subclass a C++ abstract class in Java using JNI.
Problems I face:
My aim is to provide Java implementation for the virtual methods in C++ by subclassing the abstract C++ class.
I have loaded the native library and I'm trying to declare the native methods.
The C++ methods have keyword 'virtual'. When I declare the native functions in Java after loading the C++ library, 'virtual' is not recognized. What is wrong here?
Any help is appreciated. I'm a newbie to JNI. Thanks in advance.
Let's consider we have a C++ class:
class iVehicle
{
public:
virtual void Run() {}; // not-pure virtual here for simplicity of a wrapper, but could be pure (see the end of the post)
virtual int GetSize() const; // we want to reuse it in Java
};
We want to create a class Bot in Java that extends class iVehicle in the sense that calls to super invoke the C++ code from iVehicle::GetSize() and, from the C++ point of view, we can use the instances of Bot as iVehicle* variables. That's tough since C++ provides no good built-in functionality for reflection.
Here is one possible solution.
To use C++ class in Java we need to generate a Java wrapper, i.e:
class iVehicle
{
public void Run() { Native_Run(); }
public int GetSize() { return Native_GetSize(); }
private native void Native_Run();
private native int Native_GetSize();
// typecasted to pointer in C++
private int NativeObjectHolder;
// create C++ object
native static private int CreateNativeObject();
}
The usage in Java is simple:
class Bot extends iVehicle
{
public int GetSize()
{
if ( condition ) return 0;
// call C++ code
return super.GetSize();
}
}
However, there is a C++ part to this code:
static jfieldID gNativeObjectHolderFieldID;
JNIEXPORT void JNICALL Java_com_test_iVehicle_Run( JNIEnv* env, jobject thiz )
{
int Value = env->GetIntField(thiz, gNativeObjectHolderFieldID);
iVehicle* Obj = (iVehicle*)Obj;
// todo: add checks here, for NULL and for dynamic casting
Obj->Run();
}
The similar code is for GetSize().
Then creating an instance of Java's Bot you have to call CreateNativeObject() and assign the returned value to the NativeObjectHolder field.
JNIEXPORT int JNICALL Java_com_test_iVehicle_CreateNativeObject( JNIEnv* env, jobject thiz )
{
iVehicle* Obj = new iVehicle;
return (int)Obj;
}
So, this is the scheme. To make this work you will need to add the destruction code and to parse C++ classes to generate all this glue code.
Added:
In case where iVehicle is actually abstract you will have to generate a non-abstract wrapper that you are able to instantiate:
class iVehicle
{
virtual void Run() = 0;
}
class iVehicle_Wrapper: public iVehicle
{
virtual void Run() { ERROR("Abstract method called"); };
}
And instantiate iVehicle_Wrapper in CreateNativeObject(). Vuala! You have inherited an abstract C++ class in Java.

Java JNI LoadLibrary protected dll

I created JNI export dll with visual c++ with one simple function. it work correctly when i use it in my java code with LoadLibrary method.
but when i use Unikey Enveloper and protected this dll it not work in java and this error appear
Invalid access to memory location
when i test this protected dll with visual c++ console application it work correctly.
how can I use protected dll in java LoadLibrary Method?
Visual C++ Code:
extern "C" {
JNIEXPORT jint JNICALL Java_Bikaran_Start_JniTestFunction(JNIEnv *env, jclass c, jint a, jint b)
{
return a + b;
}
}
JAVA Code :
package Bikaran;
public class Start {
public static native int JniTestFunction(int s, int s1);
public static void main(String[] args) {
System.loadLibrary("...");
System.out.println(JniTestFunction(1,2));
}
}

How can I send multiple strings from android Java to JNI?

I am trying to follow this
I have declared the JNI function as
JNIEXPORT void JNICALL Java_com_mypackage_myapp_MyJavaClass_Fun(JNIEnv* env, jobject object, jobjectArray stringArray)
And the corresponding Java function in MyJavaClass is declared as:
public native void Fun(String[] strArray);
But its not working for me as I keep getting run time error:
No implementation found for void com.mypackage.myapp.MyJavaClass.Fun(java.lang.String[])
I have also tried declaring Fun as
public native void Fun(List<String> strArray);
And
public native void Fun(ArrayList<String> strArray);
but these also result in same run time error

UnsatisfiedLinkError - how to create the c++-DLL?

I am trying to generate a dll which I can access from java via JNA.
I just try a simple one:
CPP:
void Initialize()
{
std::cout<< "Hello World!";
}
iostream is also included and after compiling I get: CreateDll.dll
Via Visual Studio I can generate now a *.dll.
which I try loading into Java like:
public class mainRoutine {
public static void main(String[] args) {
NativeWrapper INSTANCE = (NativeWrapper) Native.loadLibrary("CreateDll" , NativeWrapper.class);
INSTANCE.Initialize();
}
static {
System.setProperty("jna.library.path", "C:\\workspace\\JNA");
}
}
There is also another Interface:
import com.sun.jna.Library;
public interface NativeWrapper extends Library {
void Initialize();
}
So but now running the Java function I get the error,
java.lang.UnsatisfiedLinkError:
Error looking up function 'Initialize':
The specified procedure could not be found.
What am I missing?
PS: I know there are many topics, but trying for a day already I have not found the solution. Please help me.
You need to both export and (if using C++) un-decorate the function name.
On windows, functions are typically made available for export with __declspec(dllexport).
On any platform, to ensure a function is exported in unmanagled form, you must use extern "C".
Specifically:
extern "C" void __declspec(dllexport) Initialize() { ... }
There are other ways to designate exported functions, but this is probably the most common and straightforward to use. If you don't use extern "C", your function will look something like InitializeZ#ASDF#, where the additional garbage characters are used by the compiler and linker to make a given function uniquely recognizable based on its calling signature.
Are you exporting the symbol:
void _declspec(dllexport) Initialize()
{
std::cout<< "Hello World!";
}
What if there is a class to be implemented ? where the .h file looks like this:
namespace simpleDLLNS
{
class simpleDLL
{
public:
char giveVoidPtrGetChar(void* param);
int giveIntGetInt(int a);
void simpleCall(void);
int giveVoidPtrGetInt(void* param);
};
}
Where should extern "C" void __declspec(dllexport) be used ?
I used it when implementing the functions. but when i opened the dll, it looked like this:
?simpleCall#simpleDLL#simpleDLLNS##QAEXXZ

Categories

Resources