JNI syntax in Android NDK - android

Quick question about the JNI syntax in Android NDK
This is my function name in c++ code
JNIEXPORT void JNICALL Java_ogs_test_ogskcg_ogstranspose(JNIEnv * env, jobject obj)
And my log cat error msg
09-10 01:08:38.476: WARN/dalvikvm(278): No implementation found for native Logs/test/ogskcg;.ogstranspose ()V
Can you let me know is it the name prefix problem or something else

JNIEXPORT void JNICALL Java_ogs_test_ogskcg_ogstranspose(JNIEnv * env, jobject obj)
Should not be (you missed a L):
JNIEXPORT void JNICALL Java_Logs_test_ogskcg_ogstranspose(JNIEnv * env, jobject obj)

You try this("void Java_ogs_test_ogskcg_ogstranspose(JNIEnv * env, jobject obj)") decleration. and use extern keyword
extern "C"{
void Java_ogs_test_ogskcg_ogstranspose(JNIEnv * env, jobject obj)
}

Related

Change function name in a .so library

I only have 1 .so file from old project.
How can I use this file without creating the same package in project or module ?
Actually, you don't need to change function name in .so file. You can use dlopen to load your .so library dynamically at runtime and dlsym to get pointer for you YOUR_FUNCTION_NAME() and then call YOUR_FUNCTION_NAME() by pointer. For do that in your current project you can create "wrapper" like that:
public class OldSoHelper {
public static native void loadOldSo();
public static native <TYPE_OF_RESULT> runFunFromOldSo(<PARAMETERS>);
public static native void unloadOldSo();
}
and in corresponding .c/.cpp file of current project (e.g. native-lib.cpp by default):
void *handle;
<TYPE_OF_OLD_FUNCTION> (*old_fun_wrapper)(<PARAMETERS_OF_OLD_FUNCTION>);
extern "C"
JNIEXPORT void JNICALL
Java_<YOUR_PACKAGE_NAME>_OldSoHelper_loadOldSo(JNIEnv *env, jclass type) {
handle = dlopen("<YOUR_OLD_SO>.so", RTLD_NOW);
old_fun_wrapper = (<TYPE_OF_OLD_FUNCTION> (*)(<PARAMETERS_OF_OLD_FUNCTION>))(dlsym(handle, "<OLD_FUNCTION_NAME_e.g._Java_com_abc_dee_Native_appInit>"));
}
extern "C"
JNIEXPORT jobject JNICALL
Java_<YOUR_PACKAGE_NAME>_OldSoHelper_runFunFromOldSo(JNIEnv *env, jclass type,
<PARAMETERS_FOR_OLD_FUNCTION>)
{
jclass ResultClass = env->FindClass("YOUR/PACKAGE/NAME/RESULT_CLASS");
jobject result = ...
jfieldID fieldId = env->GetFieldID(ResultClass, "<FIELD_NAME>", "<FILED_TYPE_LETTER>");
<TYPE_OF_OLD_FUNCTION> res = old_fun_wrapper(<PARAMETERS_FOR_OLD_FUNCTION>);
env->Set<TYPE>Field(result, fieldId , res.filed);
return result;
}
extern "C"
JNIEXPORT void JNICALL
Java_<YOUR_PACKAGE_NAME>_OldSoHelper_unloadOldSo(JNIEnv *env, jclass type) {
if (handle) {
dlclose(handle);
}
}
and from java code you can call:
...
// when you need old .so e.g. in onCreate()
OldSoHelper.loadOldSo();
...
// when you no need to call function from old .so
<TYPE_OF_RESULT> result = OldSoHelper.runFunFromOldSo(<PARAMETERS>);
...
// when you no need old .so e.g. in onDestroy()
OldSoHelper.unloadOldSo();
...

Sum two integers in JNI function return a wrong value

I am calling a native function that do a very simple summation operation, but it returns a wrong result why ?!
Here is my java code:
package com.example.sharedlibexample;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = (TextView) findViewById(R.id.text);
tv.setText("Value = " + String.valueOf(addInJNI(15, 8)));
}
public native int addInJNI(int a, int b);
static {
System.loadLibrary("hello-jni");
}
}
and this is the native code:
int Java_com_example_sharedlibexample_MainActivity_addInJNI(int a, int b) {
return a + b;
}
The result of this sum example is:
-921636135
The two first parameters in the native function should be JNIEnv* env, jobject thiz (or JNIEnv* env, jclass clazz for a static method). What your code current actually does, is that it adds the values of the env and thiz pointers, instead of the real parameters you intended to pass.
You can use javah to generate the method signatures (in the form of a header file), which also includes other attributes which may be necessary in some cases (like JNIEXPORT, JNICALL).
With help from this blog
I could find the solution by using the jint rather than int
The solution is:
Create a header file bativeLib.h
#include <jni.h>
/* Header for class com_marakana_NativeLib */
#ifndef _Included_org_example_ndk_nativeLib
#define _Included_org_example_ndk_nativeLib
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_marakana_NativeLib
* Method: add
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_example_sharedlibexample_MainActivity_addInJNI
(JNIEnv *, jobject, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
and the C lib looks like:
#include "nativeLib.h"
JNIEXPORT jint JNICALL Java_com_example_sharedlibexample_MainActivity_addInJNI
(JNIEnv * env, jobject obj, jint value1, jint value2) {
return (value1 + value2);
}

Android Studio NDK return jint

I have successfully followed this tutorial https://www.youtube.com/watch?v=kFtxo7rr2HQ to learn about building NDK apps with Android Studio.
That tutorial uses a public native String HelloJNI();
That string is set in the HelloJNI.c file
#include "com_example_myapplication_MainActivity.h"
/* Header for class com_example_myapplication_MainActivity */
/*
* Class: com_example_myapplication_MainActivity
* Method: HelloJNI
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_HelloJNI
(JNIEnv *env, jobject obj)
{
(*env)->NewStringUTF(env, "Hello from jni");
}
and loaded at runtime with
static{
System.loadLibrary("HelloJNI");
}
Now Im attempting to do the same thing but retrieve and int not a string
public native int getintONE();
I follow the same steps in the tutorial, everything works fine, now my getintONE.c reads
#include "com_example_myapplication_MainActivity.h"
/*
* Class: com_example_myapplication_MainActivity
* Method: getintONE
* Signature: ()I
*/
JNIEXPORT jint JNICALL com_example_myapplication_MainActivity_getintONE
(JNIEnv *env, jobject obj)
What is the equivelant of
JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_HelloJNI
(JNIEnv *env, jobject obj)
{
(*env)->NewStringUTF(env, "Hello from jni");
}
To return an int, not a string.
I've read through many questions here, read tutorial and documentation, most of the stuff I've seen on my research and tried were samples for returning, jint arrays, converting jint to string, and what seem to me to be more involved advanced topics.
Thanks in advance
A jint is a primitive type, so if you have included jni.h you can simply return one from the function - there is no need to allocate an Object as you were doing with NewStringUTF() for a String.
JNIEXPORT jint JNICALL com_example_myapplication_MainActivity_getintONE(JNIEnv *env, jobject obj) {
return 1; //or anything that can be cast to a jint
}

I am trying to compile my jnicode it showing error _JNIEnv::GetShortArrayElements(JNIEnv*&, _jshortArray*&, int)'

I am trying to compile my jnicode it showing error
_JNIEnv::GetShortArrayElements(JNIEnv*&, _jshortArray*&, int)'
my code is:
extern "C" JNIEXPORT jint Java_com_techgentsia_sound_Opusmain_nativeDecodeBytes (JNIEnv *env, jobject thiz,jbyteArray decoder_insrc,jshortArray decoder_out)
{
int frame_size=320;
jshort* pcm_data_decoder=env->GetShortArrayElements(env, decoder_out,0);
jbyte* opus_data_decoder=env->GetByteArrayElements(env, decoder_insrc,0);
}
the error in compiler is:
/home/clifford/opusbuild/jni/opus/com_techgentsia_sound_Opusmain.cpp:117:72: error: no matching function for call to '_JNIEnv::GetShortArrayElements(JNIEnv*&, _jshortArray*&, int)'
/home/clifford/opusbuild/jni/opus/com_techgentsia_sound_Opusmain.cpp:117:72: note: candidate is:
/home/clifford/apps/android-ndk-r10/platforms/android-9/arch-arm/usr/include /jni.h:921:13: note: jshort* _JNIEnv::GetShortArrayElements(jshortArray, jboolean*)
/home/clifford/apps/android-ndk-r10/platforms/android-9/arch-arm/usr/include/jni.h:921:13: note: candidate expects 2 arguments, 3 provided
i solved the problem change the code as below.
extern "C" JNIEXPORT jint Java_com_techgentsia_sound_Opusmain_nativeDecodeBytes (JNIEnv *env, jobject thiz,jbyteArray decoder_insrc,jshortArray decoder_out)
{
int frame_size=320;
jshort* pcm_data_decoder=env->GetShortArrayElements( decoder_out,0);
jbyte* opus_data_decoder=env->GetByteArrayElements( decoder_insrc,0);
}
we don'need to pass env in this methods
GetShortArrayElements( decoder_out,0);
GetByteArrayElements( decoder_insrc,0);
because i am writing cpp class

UnsatisfiedLinkError: Native method not found - Android

I am developing an android app using C++ code. Trying to use JNI but failed.
The code in myFirstApp.cpp
JNIEXPORT jint JNICALL Java_com_example_myfirstapp_CreateApp_findMarkersNative(
JNIEnv* env, jobject, jlong addrRgba) {
//clock_t begin = clock();
Mat& mRgb = *(Mat*) addrRgba;
Mat mgray(mRgb.rows, mRgb.cols, CV_8UC1);
cvtColor(mRgb, mgray, CV_RGBA2GRAY, 1); // the working one
clearVectors();
findSquares(mgray);
mergeRectangles();
processFilteredSquares(mgray);
drawFilteredSquaresWithoutMarker(mRgb);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Candidates %i",candidates.size());
return clusterBoundaries.size();
// clock_t end = clock();
// mgray.release();
}
In the android activity(CreateApp), I've declared the method
public native int findMarkersNative(long imgAdd);
The package name in the activity is
package com.example.myfirstapp;
The error appearing the logcat
Caused by: java.lang.UnsatisfiedLinkError: Native method not found com.example.myfirstapp.CreateApp.findMarkersNative
Your definitions seem correct. According to several similar posts, it may be because of C / C++ name mangling.
Try surrounding your methods, around where this API is defined with
extern "C" { }
for example:
extern "C" {
JNIEXPORT jint JNICALL Java_com_example_myfirstapp_CreateApp_findMarkersNative(JNIEnv* env, jobject, jlong addrRgba)
{
... function code ...
}
}
Source: Unsatisfied link error

Categories

Resources