Setting up JNI in Android Studio 3 - java

I am using JNI in an Android Studio project I am working on. Currently, I have a C++ library that looks similar to this.
#include <jni.h>
...
extern "C" {
JNIEXPORT jobject JNICALL Java_com_cerbyarms_cerbyarms_esra_camera_CameraActivity_FindFeatures(JNIEnv* env, jobject, jlong maskMat)
{
...
jclass rectClass = env->FindClass("org/opencv/core/Rect");
jmethodID rectID = env->GetMethodID(rectClass, "<init>", "(IIII)V");
return env->NewObject(rectClass, rectID, x, y, width, height);
}
}
This works. However, it is inefficient. Every time this is run, rectClass has to refind the class and other variables that remain constant in the program have to be recalculated and redefined every time function FindFeatures is called.
I came across this answer on Stack Overflow (It is not related to this question apart from the fact that it shows an example of what I am trying to do), that shows a different layout for a native file when using JNI.
It looked like this
static jclass java_util_ArrayList;
static jmethodID java_util_ArrayList_;
jmethodID java_util_ArrayList_size;
jmethodID java_util_ArrayList_get;
jmethodID java_util_ArrayList_add;
static thread_local JNIEnv* env;
void init() {
java_util_ArrayList = static_cast<jclass>(env->NewGlobalRef(env->FindClass("java/util/ArrayList")));
java_util_ArrayList_ = env->GetMethodID(java_util_ArrayList, "<init>", "(I)V");
java_util_ArrayList_size = env->GetMethodID (java_util_ArrayList, "size", "()I");
java_util_ArrayList_get = env->GetMethodID(java_util_ArrayList, "get", "(I)Ljava/lang/Object;");
java_util_ArrayList_add = env->GetMethodID(java_util_ArrayList, "add", "(Ljava/lang/Object;)Z");
}
std::vector<std::string> java2cpp(jobject arrayList) {
jint len = env->CallIntMethod(arrayList, java_util_ArrayList_size);
std::vector<std::string> result;
result.reserve(len);
for (jint i = 0; i < len; i++) {
jstring element = static_cast<jstring>(env->CallObjectMethod(arrayList, java_util_ArrayList_get, i));
const char* pchars = env->GetStringUTFChars(element, nullptr);
result.emplace_back(pchars);
env->ReleaseStringUTFChars(element, pchars);
env->DeleteLocalRef(element);
}
}
This shows a native file that has expensive and constant variables that appear to only be declared and calculated once.
How can I achieve a similar thing using only the Android Studio IDE? I don't mind having to set up external tools in the Android Studio IDE settings, but I don't want to have keep switching between Android Studio and something like CMD every time I compile my code.
Ideally, this could all be handled correctly when Make Project is hit. Is this possible in Android Studio 3?

You are 100% right, some JNI values beg to be cached and reused. Class references and method IDs are good examples. Please remember that FindClass() returns a local reference, so you need NewGlobalRef() for each class you keep in cache.
Android Studio does not help us with this setup, and I am not aware of reliable tools that can do such refactoring for us. You can learn good practices from open source code, e.g. from WebRTC JNI wrapper or from Spotify JNI helpers.
Android Studio can only keep track of the native methods, not of the cached objects, conversions, etc.

Related

Android invoke JVMTI from java side via JNI failed, pointer is NULL

I had wrote a agent to use the JVMTI on android 9. Code like this, I create an AgentFunction object to monitor the VM. It work's fine.
AgentFunction *agent = 0;
JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *vm, char *options, void *reserved) {
agent = new AgentFunction();
agent->Init(vm);
agent->ParseOptions(options);
agent->AddCapability();
agent->ShowCapabilities();
agent->RegisterEvent();
return JNI_OK;
}
Then i want export some interface to java, than user can invoke the JVMTI function directly.
private native boolean applyChangeNative(List<ClassInfo> classes);
The JNI fumction in agent.so
extern "C"
JNIEXPORT jboolean JNICALL Java_com_cc_jvmtiagent_JVMTIFunction_applyChangeNative
(JNIEnv *jniEnv, jobject, jlong jvmti, jobject classInfo) {
...
jvmtiClassDefinition *def = new jvmtiClassDefinition[total_classes];
agent->RedefineClasses(total_classes, def);
}
But when invoke the native method applyChangeNative from JAVA, the agent->RedefineClasses crash caused by agent is null. After my test, i found i can't access the object create in JVMTI from JNI.
I had read the JDK souce code , I found it have an InvocationAdapter.cc, When Agent_OnAttach it create the JPLISAgent, then create java.lang.instrument.Instrumentation and save the JPLISAgent in it. Each function from Java will take the JPLISAgent point.
But i want to known , why access the JVMTI object is NULL directly from JNI?
Resolved:
If you want invoke the agent method via JNI, you should use System.Load(agentPath) instead of System.LoadLibrary(libName). It need use the same so file.
It work's on Android 9 and 10, But on Android 8.x, Can't access the agent, i do not know why.

What is the JNI flow for native Thread class functions? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I am new to the JNI area and my aim is to study the native methods of java.lang.Thread such as registerNatives and start0() so that I get to understand at the OS level what are the OS operations that happen when a Thread is
a)created
b)started
So I cam across various tutorials for JNI so as to understand just the basics. It looks like there are 4 main steps
a) write the declaration of the native method(s) in a class (like start0() in Thread.java)
b) use javah tool in jdk/bin to generate a .h file
c) include these generated .h files and other common .h files in jdk/include to the c/c++ project env
d) write the required c++ function.
Please correct me if I have missed a step.
Questions-
1) When I apply the step b) to a standard java file like Thread.java, I couldn't find something like Thread.h in the JDK and it's source. What should be the exact location of the same ? I got the link of Thread.h in apache harmony http://svn.apache.org/repos/asf/harmony/enhanced/sandbox/bootjvm/bootJVM/jni/src/harmony/generic/0.0/include/java_lang_Thread.h and this is exactly the same file which I expected to be there in jdk.
2) I see a file called Thread.C at jdk\src\share\native\java, this file includes the file I expected in point number 1, java_lang_Thread.h. Thread.C file contains code
Java_java_lang_Thread_registerNatives(JNIEnv *env, jclass cls)
{
(*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods));
}
Ideally I would have expected this code to be there in Thread.h, why is it there in Thread.C and what is it's significance ?
3)There is a file called thread.cpp at openjdk\hotspot\src\share\vm\runtime and it contains all the method definitions, now starting from Thread.h
JNIEXPORT void JNICALL Java_java_lang_Thread_start(JNIEnv *, jobject);
how can we map it to Thread.start because I couldn't notice a mapping between start0() to start().
4) Since I am a java programmer and may have hard time understanding c++ code in Thread.CPP, could someone guide me to a link which may contain theory of these methods like set_stack_base(NULL) etc ?
I do not have a link to the jdk or the java threading source. Perhaps if you provided one, I could solve your problem.
However, what I gathered from your question is: "How does the Thread.h link to the Thread.cpp?" If that is what you are asking then think of it this way:
Thread.h just contains a bunch of declarations. Similar to that of a Java interface.
Thread.c contains the implementation of that interface.
As for my second guess as to what you're asking: "How does java create a native thread?".
If I had to take a huge guess at Java creating a thread on Windows, I'd say the definition is either written using WINAPI (windows only) or the C++ stl (portable):
Suppose you have a java Threading class:
public class Threading {
static{ System.LoadLibrary("Threading"); }
private Runnable r = null;
private native void StartNativeThread(Runnable r);
public Threading(Runnable r) {
this.r = r;
}
public void start() {
StartNativeThread(this.r);
}
}
The above class is passed a runnable in its constructor. When you call start, it calls the native function "StartNativeThread" and that function is going to take the runnable as a parameter.
On the C++ side, it will create a thread and that thread will call Runnable.run which it got from the java side.
WINAPI-C++:
//object that will hold all thread information.
struct ThreadParams
{
JNIEnv* env;
jobject runnable;
};
//function that the thread will call.
DWORD __stdcall RunnableThreadProc(void* ptr)
{
ThreadParams* p = reinterpret_cast<ThreadParams*>(ptr); //get our thread info from the parameter.
JNIEnv* env = p->env; //grab our env.
jobject runnable = p->runnable; //grab our runnable object.
delete p; //since we allocated on the heap using new, we must delete from the heap.
//this is because c++ does not have garbage collection.
jclass RunnableInterface = env->GetObjectClass(runnable); //get our java runnable interface instance.
jmethodID Run = env->GetMethodID(RunnableInterface, "run","()V"); //get the run method function pointer.
env->CallObjectMethod(RunnableInterface, Run); //call RunnableInterface.run();
}
JNIEXPORT void JNICALL Java_JNIExample_StartNativeThread(JNIEnv* env, jobject obj, jobject runnable)
{
ThreadParams* ptr = new ThreadParams(); //create an object to store our parameters.
ptr->env = env; //store the env parameter.
ptr->runnable = runnable; //store the runnable object.
//create a thread that calls "RunnableThreadProc" and passes it "ptr" as a param.
CreateThread(0, 0, RunnableThreadProc, reinterpret_cast<void*>(ptr), 0, 0);
}
Now the above looks quite complicated to be completely honest but that is what WINAPI is. It is an API written for windows in the C Language.
If you have a C++x11 compiler and wish to avoid winapi and use STL-C++, this can be done in a couple lines.
Assume that we have the same java class as above, then our function becomes:
JNIEXPORT void JNICALL Java_JNIExample_StartNativeThread(JNIEnv* env, jobject obj, jobject runnable)
{
std::thread([&]{
jclass RunnableInterface = env->GetObjectClass(runnable);
jmethodID Run = env->GetMethodID(RunnableInterface, "run","()V");
env->CallObjectMethod(RunnableInterface, Run);
}).detach();
}
Note that [&]{....} is a Lambda Function. It means a function that can be created inside of another function or parameter.
The above can also be translated / is equivalent to:
void ThreadProc(JNIEnv* env, jobject runnable)
{
jclass RunnableInterface = env->GetObjectClass(runnable);
jmethodID Run = env->GetMethodID(RunnableInterface, "run","()V");
env->CallObjectMethod(RunnableInterface, Run);
}
JNIEXPORT void JNICALL Java_JNIExample_StartNativeThread(JNIEnv* env, jobject obj, jobject runnable)
{
std::thread(ThreadProc, env, obj).detach();
}
Now implementing other things like stop and pause is just as easy. You simply do that on the java side inside your runnable. OR you can do it on the C++ side using WINAPI's TerminateThread and WaitObject and the likes. OR if you choose to use STL-C++ then you'd use an std::condition_variable.
I hope that clears up some things. If you have any further questions, you can just post a comment or make a new thread. Up to you. Otherwise, if I missed something or interpreted your question wrong, then please clarify it.
EDIT.. So for the actual implementation, we can see that Thread.c includes jvm.h. Thus we must find jvm.h and jvm.cpp.
A quick search comes up with:
Thread.h: http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/00cd9dc3c2b5/src/share/native/java/lang/Thread.c
JVM.h: http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/tip/src/share/vm/prims/jvm.h
JVM.cpp: http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/9b0ca45cd756/src/share/vm/prims/jvm.cpp
If we now search for any of the functions from thread.c.. We can see in thread.c that start0 is mapped to JVM_StartThread, and all other thread functions is mapped to JVM_XXXXSomeThreadFunc...
We must now look for these JVM_ functions within JVM.h and JVM.cpp. Once found, you have the source of how it is all done.

android ndk wrapped c++ file get android system file path

I have some code written in c++ by android JNI.
in one export function
"extern "C" JNIEXPORT int JNICALL Java_com_android_mymapsforge_create(JNIEnv *env, jobject obj)
{
...
ifstream infile("C:\\Users\\li\\Documents\\Visual Studio 2010\\Projects\\importANN\\Debug\\nodes.csv");
string line;
int index = 0;
while( getline( infile, line ))
{
....
}
}
when i using those original c++ code, i test under vs2010. Either i assign the infile() parameters with a fixed file path, or using some c++ get_file_path function, it's a thing related windows system, there is no problem. both work.
But now I want to using these code under JNI using by android. So the file path system change to android and some function need be adjusted.
My problem arise: because the code is using at last by my android java code under a android app, so the "C:\Users\li\Documents\Visual Studio 2010\Projects\importANN\Debug\nodes.csv", no longer take effect, it may be change to "/mnt/sdcard/somefolder/nodes.csv"
but i have experience when i in android app give a fixed file path it tell my some error, so under android jave envi, i using below code to get file path, similar code here:
String mpath ;
mpath = Environment.getExternalStorageDirectory().getPath();
mapView.setMapFile(new File(mpath+"/"+"berlin.map"));
(omit the filename , i just want to tell the method i use)
But these android code must can not use in my c++ wrapping function Java_com_android_mymapsforge_create,
So my question is :
how to cope with the file(android system) path things under the c++ export function? For example, i put the "nodes.csv" under my sdcard root folder, and want to do some processing under the JNI exported c++ function?
The easiest way is to pass the path as an argument of the function.
extern "C" JNIEXPORT int
JNICALL Java_com_android_mymapsforge_create(JNIEnv *env, jobject, jstring path)
Then you can turn jstring path to char* using JNI converting jstring to char *.
The second way is to call Android Environment.getExternalStorageDirectory().getPath() from JNI function like described here - Call a static java method of another package from native code.

Java JNI "symbol lookup error" with c++ library

I am building a small app on a raspberry pi.
I have a JVM which tries to access a C++ Library called "RCSwitch"
I created a JavaClass
public class NativeRCSwitchAdapter {
private static final NativeRCSwitchAdapter instance = new NativeRCSwitchAdapter();
public static NativeRCSwitchAdapter getInstance(){
return instance;
}
private NativeRCSwitchAdapter(){};
static{
String path = NativeRCSwitchAdapter.class.getProtectionDomain().getCodeSource().getLocation().getPath();
System.load(path + "NativeRCSwitchAdapter.so");
}
// methods to redirect to native layer (C++)
public native void switchOn(String group, String channel);
public native void switchOff(String group, String channel);
}
I then ran javac & javah to have java generate my header file for me.
I created a c++ file:
#include "NativeRCSwitchAdapter.h"
#include "RCSwitch.h"
#include <stdio.h>
#include <iostream>
using namespace std;
JNIEXPORT void JNICALL Java_NativeRCSwitchAdapter_switchOn(JNIEnv * env, jobject obj, jstring jsGroup, jstring jsChannel ){
cout<<"teststring output"<<endl;
const char *csGroup = env->GetStringUTFChars(jsGroup, 0);
const char *csChannel = env->GetStringUTFChars(jsChannel, 0);
char sGroup[6];
char sChannel[6];
for (int i = 0; i<5; i++) {
sGroup[i] = csGroup[i];
sChannel[i] = csChannel[i];
}
sGroup[5] = '\0';
sChannel[5] = '\0';
cout<<"ONON"<<endl;
cout<<sGroup<<endl;
cout<<sChannel<<endl;
RCSwitch mySwitch = RCSwitch();
//for testing purposes set to the ELRO Power Plugs
mySwitch.setPulseLength(300);
mySwitch.enableTransmit(0);
mySwitch.setRepeatTransmit(3);
mySwitch.switchOn(sGroup, sChannel);
}
Now this file uses the RCSwitch library which in turn uses the wiringPi library.
Now if i compile i run this:
g++ -shared -I/usr/jdk1.8.0/include -I/usr/jdk1.8.0/include/linux NativeRCSwitchAdapter.cpp -o NativeRCSwitchAdapter.so
Yet I get this error if start everything from java: (simple main, create an instance of my object and run the switchOn()
java: symbol lookup error: /home/pi/applications/Pi-jAutomation433/RCSwitchJNIWrapper/src/NativeRCSwitchAdapter.so: undefined symbol: _ZN8RCSwitchC1Ev
It has been time, since i last coded in C, so please forgive me but I believe it has something to do with the the linking phase of the compiler? Or does the compiler automatically check all dependencies and then their deps until no further dependencies are found and it then links it all nicely together and wraps it in an app?
Oh here is the repo to have an in depth look if anybody cares:
Github repo
Thanks for any help coming my way!
UPDATE
Okay so I managed to get this error away. Turns out (well I kinda knew that already but yeah) I am quiet a duphus when it comes to C++ compiler knowledge. Anyways I managed to get the error changed. I didn't know I had to explicitly tell g++ to include RCSwitch.cpp as well. Okay so now I did. Next error ;-)
I guess this time it should be fairly easy to tackle. I get an undefined symbol "pinMode".
This symbol is part of the wiringPi library. Do I have to include ALL c librarys that are executed in my java file? Or only the one I access and anything after that doesnt matter to java?
Your native function declaration is getting mangled by the c++ compiler. Add extern "C" around your declarations to clear up the issue.
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
JNIEXPORT void JNICALL Java_NativeRCSwitchAdapter_switchOn(JNIEnv * env, jobject obj, jstring jsGroup, jstring jsChannel ){
#ifdef __cplusplus
}
#endif /* __cplusplus */
Edit:
You need to include all other objects/libraries into your creation of the shared library.
See this Dynamic Link Library Q/A.

How to query the high-resolution performance counter

Good morning,
i need to obtain the value of the CPUs high-resolution performance counter in order to measure delay between various software applications. In my c(++|#) i use the
BOOL WINAPI QueryPerformanceCounter(
__out LARGE_INTEGER *lpPerformanceCount
);
WinApi call. What is the proper way to obtain the counter from java. I have search jna without success. I know this is a platform specific issue, but maybe there is a quicker way than writing my own jni wrapper?
Best wishes,
Armin
How about using System.nanoTime? I think that already uses the performance counters of the machine and there is no need to write a native wrapper.
Update: According to this article on clocks and timers in the jvm in the section "Clocks and Timers on Windows"
System.nanoTime() is implemented using the QueryPerformanceCounter/QueryPerformanceFrequency API
Here is the native wrapper code
1) File W32Call.java
package jmSense.Native; public class W32Call {
public native static long QueryPerformanceCounter( );
public native static int QueryPerformanceCounterInt32( );
2) run java h to create the include file
3) Create a dll "My Native Extensions.dll" from
#include "stdafx.h"
#include "windows.h"
#include "jmSense_Native_W32Call.h"
JNIEXPORT jlong JNICALL Java_jmSense_Native_W32Call_QueryPerformanceCounter(JNIEnv *, jclass)
{
LARGE_INTEGER g_CurentCount;
QueryPerformanceCounter((LARGE_INTEGER*)&g_CurentCount);
return g_CurentCount.QuadPart;
}
JNIEXPORT jint JNICALL Java_jmSense_Native_W32Call_QueryPerformanceCounterInt32(JNIEnv *, jclass)
{
LARGE_INTEGER g_CurentCount;
QueryPerformanceCounter((LARGE_INTEGER*)&g_CurentCount);
return g_CurentCount.LowPart;
}
4) Use it like this:
System.loadLibrary("My Native Extensions");
System.out.println(W32Call.QueryPerformanceCounter());
fine

Categories

Resources