0

I want to call native code from java in case of native activity.

Suppose I have game engine in engine.so. Now I want to add speech recognition. I added java wrapper-class and start speech recognition from native code via jni. I want to return result to native side. Following jni examples I declared native method in java class and call it when recognition finished:

public native void onSpeechRecognized ( String value );

I implemented this method in engine.so. Of course I don't load engine.so with System.loadLibrary as it's already loaded. But java code doesn't sees method implementation, reporting:

FATAL EXCEPTION: main
java.lang.UnsatisfiedLinkError: onSpeechRecognized
    at com.company.appname.SpeechRecognizerWrapper.onSpeechRecognized(Native Method)
    at com.company.appname.SpeechRecognizerWrapper$SpeechRecognitionListener.onResults(SpeechRecognizerWrapper.java:92)
    at android.speech.SpeechRecognizer$InternalListener$1.handleMessage(SpeechRecognizer.java:428)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:130)
    at android.app.ActivityThread.main(ActivityThread.java:3687)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:842)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
    at dalvik.system.NativeStart.main(Native Method)

nm utility shows that engine.so contains Java_com_company_appname_SpeechRecognizerWrapper_onSpeechRecognized
Signature is generated with javah.
My Android.mk

PROJ_PATH := $(call my-dir)
LIB_PATH := $(PROJ_PATH)/../../../../../Smart/Lib

include $(LIB_PATH)/Log/Projects/android/jni/Android-prebuilt.mk

...

LOCAL_PATH := $(PROJ_PATH)/../../../../../Smart/Smart
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := \
    $(PROJ_PATH)/../../../../../Smart \
    $(LIB_PATH)/Hash
LOCAL_MODULE    := smart
LOCAL_SRC_FILES := Animation/TextureAnimation.cpp
LOCAL_SRC_FILES += Base/Director.cpp

...

LOCAL_CFLAGS += -DNDEBUG -O3 -mcpu=cortex-a8 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -std=gnu++11
LOCAL_LDLIBS := -llog -landroid -lGLESv2 -lEGL -lOpenSLES
LOCAL_STATIC_LIBRARIES := android_native_app_glue Slb freetype Image FileSystem Noise Log Math Threads SharedPtr vmath png jpeg ScriptEngine QuestEngine Time tremolo

include $(BUILD_SHARED_LIBRARY)

$(call import-module,android/native_app_glue)

So why java side doesn't sees native side implementation?

Sergei Ivanov
  • 103
  • 1
  • 9
  • maybe that method is static in your engine.so then you should declare it like this public static native void onSpeechRecognized (String value); – Cristian Olaru Jan 29 '15 at 22:27
  • no, it isn't static `JNIEXPORT void JNICALL Java_com_company_appname_SpeechRecognizerWrapper_onSpeechRecognized (JNIEnv *, jobject, jstring);` – Sergei Ivanov Jan 29 '15 at 23:30
  • read here http://developer.android.com/training/articles/perf-jni.html#faq_ULE maybe you will find the problem yourself – Cristian Olaru Jan 29 '15 at 23:38
  • thanks for link, but nothing helps. With solutions like hello-jni everithing is clear. But I have not found anything like my case. I don't understand where implementation must be located - in separate library or in same where android_main is located – Sergei Ivanov Jan 30 '15 at 00:48
  • sorry I can't do more to help, but I could give you this video that helped me when I started to use native code in my apps https://www.youtube.com/watch?v=YV0zSPVSL1E&index=10&list=PL0C9C46CAAB1CFB2B – Cristian Olaru Jan 30 '15 at 01:12
  • share your Android.mk details for this file – NovusMobile Jan 30 '15 at 06:47

2 Answers2

0

Don't know why java wrapper-class can't see native function, but I resolved that problem just using RegisterNatives from native code.

Sergei Ivanov
  • 103
  • 1
  • 9
0

I notice that you are compiling .ccp files rather than plain C. For jni to be able to find a function automatically based on the function name (as opposed to being registered with RegisterNatives), the name of the function in the object file has to follow a specific pattern.

Is it possible that you did not declare the functions "extern C" to prevent C++ name mangling (this is something C++ does to re-name functions in the object file so that they include type information, which will cause jni to fail to find the function because the function name in the object file no longer fits the correct pattern).

If so, you may be able to fix the problem by surrounding the functions you want to call from JNI with:

extern "C" { <your function here> }

See, e.g., this SO answer:

UnsatisfiedLinkError for native cpp function in Android app (ndk)

Your output from the nm utility above does not seem to show the complete line nm printed for the function. If there is gibberish on either side of the function name in the raw nm output, that may indicate that the function is not "extern C" and that name mangling is the source of your trouble.

Community
  • 1
  • 1
1203_dube
  • 214
  • 1
  • 3